در دنیای وسیع برنامهنویسی پایتون، مجموعهای از ویژگیها وجود دارد که اغلب توسط مبتدیان مورد توجه قرار نمیگیرند، اما در اکوسیستم زبان اهمیت قابل توجهی دارند.
روش های جادویی مجموعه ای از روش های پیش استdefinیت شده در پایتون که عملکرد نحوی خاصی را ارائه می دهد. آنها به راحتی با خط تیره های دوتایی خود در ابتدا و انتهای آنها شناخته می شوند __init__, __call__, __len__
… و غیره.
متدهای جادویی به اشیاء سفارشی اجازه میدهند تا رفتاری مشابه انواع پایتون داخلی داشته باشند.
در این مقاله به توابع قدرتمند dunder می پردازیم. ما هدف آنها را بررسی خواهیم کرد و در مورد استفاده از آنها بحث خواهیم کرد.
چه یک مبتدی پایتون یا یک برنامه نویس باتجربه باشید، این مقاله قصد دارد تا درک جامعی از توابع Dunder به شما ارائه دهد و تجربه کدنویسی پایتون شما را کارآمدتر و لذت بخش تر کند.
به یاد داشته باشید که جادوی پایتون نه تنها در سادگی و تطبیق پذیری آن، بلکه در ویژگی های قدرتمند آن مانند توابع Dunder نیز نهفته است.
شاید ابتدایی ترین عملکرد dunder از همه باشد. این روش جادویی است که پایتون به طور خودکار هر زمان که یک شی جدید ایجاد می کنیم (یا همانطور که از نام آن پیداست، مقداردهی اولیه می کنیم) آن را فراخوانی می کند.__init__
پیتزا کلاس:
def __init__(خود، اندازه، تاپینگ):
self.size = اندازه
self.toppings = تاپینگ
# حالا بیایید یک پیتزا درست کنیم
my_pizza = پیتزا('بزرگ'، ['پپرونی'، 'قارچ'])
print(my_pizza.size) # این چاپ خواهد شد: بزرگ
print(my_pizza.toppings) # این چاپ خواهد شد: ['pepperoni', 'Mushrooms']
در این مثال کلاسی به نام Pizza ایجاد می شود. ما تابع __init__ خود را به گونه ای تنظیم می کنیم که پارامترهایی را که باید در زمان مقداردهی اولیه مشخص شوند را شامل شود و آنها را به عنوان ویژگی های شی سفارشی خود تنظیم کنیم.
در اینجا، برای نشان دادن نمونه کلاس استفاده می شود. بنابراین وقتی self.size = اندازه را می نویسیم، می گوییم: "هی، این شی پیتزا یک اندازه ویژگی دارد size
و من میخواهم هنگام ایجاد شیء به هر اندازهای باشد که ارائه کردم».
این روش جادویی پایتون است که به ما اجازه می دهد defiیک توضیح برای آیتم سفارشی ما.
وقتی یک شی را چاپ می کنید یا با استفاده از آن به رشته تبدیل می کنید str()
، پایتون بررسی کنید که آیا دارید defiروشی را ارائه کرد __str__
برای کلاس آن شی
اگر چنین است، از این روش برای تبدیل شی به رشته استفاده کنید.
میتوانیم مثال پیتزای خود را به یک تابع بسط دهیم __str__
به شرح زیر:
class Pizza: def __init__(self, size, toppings): self.size = size self.toppings = toppings def __str__(self): return f"A {self.size} pizza with {', '.join(self.toppings )}" my_pizza = پیتزا('large', ['pepperoni', 'mushrooms']) print(my_pizza) # این چاپ خواهد کرد: یک پیتزا بزرگ با پپرونی، قارچ
__repr__
تابع __str__ بیشتر یک روش غیررسمی برای توصیف خصوصیات یک شی است. از سوی دیگر، __repr__ برای ارائه توضیحات رسمی تر، دقیق تر و بدون ابهام از شی سفارشی استفاده می شود.
اگر تماس بگیرید repr()
روی یک شی یا فقط نام شی را در کنسول تایپ کنید، پایتون به دنبال یک متد خواهد بود __repr__
.
Se __str__
این نیست definite، پایتون استفاده خواهد کرد __repr__
به عنوان پشتیبان هنگام تلاش برای چاپ شی یا تبدیل آن به رشته. بنابراین اغلب ایده خوبی است defiحداقل تمام شود __repr__
، حتی اگر این کار را نکنید defiبه پایان می رسد __str__
.
در اینجا ما چگونه می توانیم defiتمام کردن __repr__
برای مثال پیتزا ما:
پیتزا کلاس:
def __init__(خود، اندازه، تاپینگ):
self.size = اندازه
self.toppings = تاپینگ
def __repr__(خود):
بازگشت f"Pizza('{self.size}', {self.toppings})"
my_pizza = پیتزا('بزرگ'، ['پپرونی'، 'قارچ'])
print(repr(my_pizza)) # این چاپ خواهد شد: پیتزا ('بزرگ'، ['pepperoni'، 'قارچ'])
__repr__
رشته ای را به شما می دهد که می توانید آن را به عنوان دستور پایتون اجرا کنید تا شی پیتزا را دوباره بسازید، در حالی که __str__
توصیف انسانی تری به شما می دهد. امیدوارم به شما کمک کند تا این روشهای دودر را کمی بهتر بجوید!
در پایتون، همه ما می دانیم که امکان اضافه کردن اعداد با استفاده از عملگر وجود دارد +
، به عنوان 3 + 5
.
اما اگر بخواهیم نمونه هایی از یک شی سفارشی اضافه کنیم، چه؟
تابع dunder __add__
به ما این امکان را می دهد که این کار را انجام دهیم. این فرصت را به ما می دهد defiرفتار اپراتور را اصلاح کنید +
در موارد شخصی ما
به نفع قوام، فرض کنیم که می خواهیم defiنیت رفتار از +
در نمونه پیتزای ما فرض کنید هر زمان که دو یا چند پیتزا را با هم اضافه می کنیم، به طور خودکار تمام رویه های آنها را با هم ترکیب می کنیم. در اینجا ممکن است به نظر برسد:
پیتزا کلاس:
def __init__(خود، اندازه، تاپینگ):
self.size = اندازه
self.toppings = تاپینگ
def __add__(خود، دیگری):
اگر نه به عنوان مثال (سایر، پیتزا):
افزایش TypeError ("شما فقط می توانید یک پیتزا دیگر اضافه کنید!")
new_toppings = self.toppings + other.toppings
پیتزای برگشتی (اندازه خود، تاپینگ های جدید)
# بیایید دو پیتزا درست کنیم
pizza1 = پیتزا('بزرگ'، ['پپرونی'، 'قارچ'])
pizza2 = پیتزا ('بزرگ'، ['زیتون'، 'آناناس'])
# و حالا بیایید آنها را "اضافه کنیم".
ترکیبی_پیتزا = پیتزا1 + پیتزا2
print(combined_pizza.toppings) # با این کار چاپ می شود: ['pepperoni'، 'قارچ'، 'زیتون'، 'pineapple']
مشابه Dunder __add__
، ما هم می توانیم definite دیگر توابع حسابی مانند __sub__
(با تفریق با استفاده از عملگر -
) و __mul__
(برای ضرب با استفاده از عملگر *
).
این روش dunder به ما این امکان را می دهد defiنیش چه عملکردی دارد len()
باید برای اقلام سفارشی ما بازگشت.
پایتون استفاده می کند len()
برای بدست آوردن طول یا اندازه یک ساختار داده مانند یک لیست یا رشته.
در زمینه مثال ما، میتوان گفت که "طول" پیتزا به تعداد مواد رویهای است که دارد. در اینجا نحوه اجرای آن آمده است:
پیتزا کلاس:
def __init__(خود، اندازه، تاپینگ):
self.size = اندازه
self.toppings = تاپینگ
def __len__(خود):
لنز برگشتی (self.toppings)
# بیایید یک پیتزا درست کنیم
my_pizza = پیتزا('بزرگ'، ['پپرونی'، 'قارچ'، 'زیتون'])
print(len(my_pizza)) # این چاپ خواهد شد: 3
در روش __len__ فقط طول لیست را برمی گردانیم toppings
. اکنون، len(my_pizza)
به ما می گوید که چند تاپینگ روی آن وجود دارد my_pizza
.
این روش dunder اجازه می دهد تا اشیا تکرار شوند، یعنی می توان از آن در یک حلقه for استفاده کرد.
برای انجام این کار، ما نیز باید defiعملکرد را تمام کنید __next__
، این برای استفاده می شود defiبه رفتاری پایان دهید که باید مقدار بعدی را در تکرار برگرداند. علاوه بر این، در صورت وجود هیچ عنصر دیگری در دنباله، باید به تکرار شونده سیگنال دهد. ما معمولاً با ایجاد یک استثنا به این امر دست مییابیم StopIteration
.
برای مثال پیتزا، فرض کنید میخواهیم رویهها را تکرار کنیم. ما میتوانیم کلاس پیتزا را تکراری کنیم defiروش دادن __iter__
:
پیتزا کلاس:
def __init__(خود، اندازه، تاپینگ):
self.size = اندازه
self.toppings = تاپینگ
def __iter__(خود):
self.n = 0
خود را برگرداند
def __next__(خود):
if self.n < len(self.toppings):
نتیجه = self.toppings[self.n]
self.n += 1
نتیجه بازگشت
دیگری:
StopIteration را افزایش دهید
# بیایید یک پیتزا درست کنیم
my_pizza = پیتزا('بزرگ'، ['پپرونی'، 'قارچ'، 'زیتون'])
# و حالا بیایید روی آن تکرار کنیم
برای تاپینگ در my_pizza:
چاپ (تاپینگ)
در این حالت حلقه for فراخوانی می کند __iter__
، که یک شمارنده را مقداردهی اولیه می کند (self.n)
و خود شی پیتزا را برمی گرداند (self)
.
سپس حلقه for فراخوانی می کند __next__
برای گرفتن هر تاپینگ به نوبه خود.
وقتی __next__
تمام چاشنی ها را برگرداند، StopIteration
یک استثنا ایجاد می کند و حلقه for اکنون می داند که دیگر هیچ تاپینگی وجود ندارد و بنابراین فرآیند تکرار را متوقف می کند.
Ercole Palmeri
دوشنبه گذشته، فایننشال تایمز از قراردادی با OpenAI خبر داد. FT مجوز روزنامه نگاری در سطح جهانی خود را صادر می کند…
میلیونها نفر برای خدمات استریم پرداخت میکنند و هزینه اشتراک ماهانه میپردازند. این عقیده رایج است که شما…
Coveware توسط Veeam به ارائه خدمات پاسخگویی به حوادث اخاذی سایبری ادامه خواهد داد. Coveware قابلیتهای پزشکی قانونی و اصلاحی را ارائه میدهد…
تعمیر و نگهداری پیش بینی شده با رویکردی نوآورانه و پیشگیرانه برای مدیریت کارخانه، بخش نفت و گاز را متحول می کند.…