چگونه به شکل امن گذرواژه‌ها را ذخیره کنیم؟

جواب خلاصه: از bcrypt استفاده کنید.

 

چرا از MD5، SHA-1، SHA256، SHA512، SHA-3 و … استفاده نکنیم؟

تمام الگوریتم‌های نامبرده، توابع هش ِ (به انگلیسی: hash function) همه‌منظوره هستند که طراحی شده‌اند تا حجم عظیمی از داده‌ها را در کم‌ترین زمان ممکن خلاصه‌سازی کنند. [مترجم: به طور مثال، یک رشته‌ی متنی بزرگ را به متنی کوچک تبدیل کنند]. این بدین معناست که این الگوریتم‌ها برای اطمینان از صحت داده‌ها عالی و برای ذخیره‌ی گذرواژه کاملا بدردنخور هستند.

یک سرور مدرن، توانایی هش‌کردن ۳۳۰مگابایت داده را در هر ثانیه، توسط الگوریتم MD5 دارد. اگر کاربران شما گذرواژه‌هایی دارند که همه به حروف کوچکند، از حروف و ارقام تشکیل شده‌اند و طولشان ۶ است، شما به راحتی می‌توانید تمام رمز‌های عبور ممکن (با مشخصات گفته‌شده) را در چیزی حدود ۴۰ ثانیه امتحان کنید.

و این حتی بدون خرج کردن یک قِران است!

اگر توانایی خرج کردن ۲۰۰ دلار آمریکا و استفاده از CUDA برای یک الی دو هفته را داشته باشید، می‌توانید سوپر کامپیوتر کوچکی برای خود فراهم کنید که توانایی امتحان کردن چیزی درحدود ۷۰۰٫۰۰۰٫۰۰۰ گذرواژه در ثانیه را دارد. و با این توان، شما می‌توانید رمز‌های عبور با شرایطی که قبلا گفتیم را نه هر ۴۰ ثانیه بلکه در هر ثانیه بشکنید!

salt‌ها به شما کمکی نخواهند کرد

توجه به این نکته مهم است که بدانید، saltها برای جلوگیری از حمله‌های لغت‌نامه‌ای (به انگلیسی: dictionary attack) و حملات بروت فورس‌ (به انگلیسی: brute-force attack) کاملا بدردنخورند. با این فرض که مهاجم salt و هش ِ دیتابیس شما را دارد، حتی اگر saltهای بسیار بزرگ هم استفاده کنید، کماکان تاثیری روی این موضوع که مهاجم با چه سرعتی توانایی تست کردن گذرواژه‌های کاندیدا را دارد، نخواهد گذاشت.

با salt یا بدون salt، اگر شما از یک تابع هش ِ همه‌منظوره، که برای سرعت طراحی شده، استفاده کنید، به دردسر بزرگی افتاده‌اید.

bcrypt مشکل را حل می‌کند

چگونه؟ به زبان ساده، فوق‌العاده کند است. bcrpyt از نوعی از الگوریتم Blowfish استفاده می‌کند و چیزی به نام ضریب کار را معرفی می‌کند که این امکان را می‌دهد تا بتوان تعیین کرد که تابع هش تا چه اندازه هزینه‌بر باشد. به همین دلیل bcrypt می‌تواند پابه‌پای قانون مور پیش برود. هرچه کامپیوتر‌ها سریع‌تر می‌شوند شما می‌توانید ضریب کار را زیادتر کنید و بدین‌ترتیب هش‌کردن نیز کندتر خواهد شد.

به طور مثال، bcrypt چقدر از MD5 کند‌تر است؟ به ضریب کار بستگی دارد. با ضریب کار ۱۲، bcrypt گذرواژه‌ی yaaa را روی لپ‌تاپ من در ۰.۳ ثانیه هش می‌کند. در سوی دیگر، MD5 همین کار را در کمتر از یک میکروثانیه انجام می‌دهد.

پس درمورد چیزی با مرتبه‌ی ۵ (۱۰ به توان ۵) برابر کندتر صحبت می‌کنیم. یعنی به جای شکستن هر گذرواژه تنها در ۴۰ ثانیه، این‌بار شکستن هر گذرواژه چیزی در حدود ۱۲ سال طول خواهد کشید. شاید شما به چنین حدی از امنیت نیاز نداشته باشید و الگوریتم مقایسه‌ی سریع‌تری را بخواهید، بدین ترتیب bcrypt امکان توازن بین سرعت و امنیت را برای شما فراهم می‌کند. از آن استفاده کنید.

 

متن بالا ترجمه‌‌ی من بود از مقاله‌ی How To Safely Store A Password.

این نوشته در سایت ویرگول: virgool.io/@mahdavipanah/bcrypt-sjj46uhqjx88

اهمیت رمزنگاری

مقاله‌ی زیر ترجمه‌ی من از نوشته‌ی بروس اشنایر (Bruce Schneier)، متخصص رمزنگاری، امنیت رایانه و حریم خصوصی و نویسنده‌ی اهل ایالات متحده آمریکا است و در سال ۲۰۱۶ در قالب مقاله‌ای در وب‌سایت شخصی او منتشر شده‌است.

 

با نفوذ همه‌گیر کامپیوتر‌ها و شبکه‌های کامپیوتری در دنیای امروز، سخت است که در اهمیت رمزنگاری اغراق کنیم. به طور خیلی ساده، رمزنگاری امنیت شما را حفظ می‌کند. زمانی که در حال انجام خدمات بانکی اینترنتی هستید رمزنگاری از جزئیات و گذرواژه‌های شما محافظت می‌کند. رمزنگاری از شنود مکالمات تلفنی شما جلوگیری می‌کند. اگر اطلاعات لپ‌تاپ خود را رمز می‌کنید – که امیدوارم اینکار را می‌کنید – رمزنگاری از داده‌های شما پس از دزدیده‌شدن کامپیوترتان محافظت می‌کند. رمزنگاری، پول و حریم شخصی شما را مصون نگه‌می‌دارد.

رمزنگاری از هویت مخالفان و فعالان سیاسی و مدنی در سراسر دنیا محافظت می‌کند. اگر شما یک روزنامه‌نگار باشید، برای ارتباط با منابع اطلاعاتی خود و یا اگر یک سازمان ناسودبر (به انگلیسی: NGO) باشید، برای محافظت از کار خود و یا اگر یک وکیل‌مدافع باشید، برای ارتباط خصوصی با موکل خود، به ابزاری حیاتی به نام رمزنگاری نیازمندید.

رمزنگاری از دولت ما محافظت می‌کند. رمزنگاری از سیستم‌های دولتی، قانون‌گذاران و ماموران اجرای قانون نیز محافظت می‌کند. رمزنگاری از مقامات رسمی ما که در داخل و یا خارج از کشور در حال کار هستند نیز محافظت می‌کند. در جریان بحث میان اپل و اف‌بی‌آی، برایم جالب بود که بدانم آیا جیمز کومی (رئیس وقت سازمان اف‌ابی‌آی) هیچ از این نکته اطلاع دارد که چه تعداد از ماموران خود او از آیفون استفاده می‌کنند؟ و بر قابلیت‌های امنیتی اپل برای محافظت از داده‌هایشان متکی هستند؟

ادامه مطلب

از تغییر نترسیم – به مناسبت خریده‌شدن گیت‌هاب توسط مایکروسافت

خریده‌شدن گیت‌هاب توسط مایکروسافت

امروز روز عجیبیه! خبر خریده‌شدن گیت‌هاب، دوست‌داشتنی‌ترین پلتفرم برای توسعه‌دهندگان و به طور خاص عاشقان ِ نرم‌افزار آزاد، توسط مایکروسافت، به طور رسمی تایید شد.

این خبر جدای از نگرانی‌هایی که می‌تونه برای ما بوجود بیاره (که البته به نظر من جای هیج نگرانی‌ای نیست و در ادامه هم بیشتر توضیح میدم) می‌تونه بهونه‌ای باشه تا خیلی مختصر، تاریخ تعامل توسعه‌دهنده‌ها، ابزار‌هاشون و درس‌هایی که برای ما داره رو باهم مرور کنیم.

ادامه مطلب

جاوااسکریپت: شیء انتخاب‌ها (options object) چیست؟

در جاوااسکریپت، اشیاء ِ انتخاب‌ها (که از این پس به آن‌ها options objects می‌گوییم) یک الگوی ِ معمول برای ِ فرستادن ِ آرگومان‌ها به یک تابع هستند. این مقاله به شرح ِ چگونگی ِ کار ِ آن‌ها و نیز دلیل ِ این که استفاده از آن‌ها باعث ِ افزایش ِ خوانایی ِ کد ِ شما می‌شود، می‌پردازد.

options object چیست؟

یک options object یک شیء ِ معمولی ِ جاوااسکریپت است، که داخل ِ آن‌ مجموعه‌ای از پارامتر‌هایی با اسم‌های ِ مشخص تعریف شده و به عنوان ورودی به یک تابع فرستاده می‌شود.

برای ِ مثال، تابع ِ jQuery.ajax از options object استفاده می‌کند. این تابع می‌تواند تا ۳۴ پارامتر ِ مختلف را بگیرد که تمام ِ آن‌ها اختیاری هستند.

$.ajax({
    url: "http://date.jsontest.com/",
    success: function (data) {console.log(data);},
    cache: true,
    timeout: 500
});

بدون ِ استفاده از یک options object فهم ِ این که هر پارامتر برای ِ چه کاری است، بسیار سخت خواهد بود:

$.ajax(
    "http://date.jsontest.com/",
    function (data) {console.log(data);},
    true,
    500
);

بسیاری دیگر از زبان‌های برنامه‌نویسی، امکانی دارند تحت ِ نام ِ «آرگومان‌های اسم‌دار» (به انگلیسی: named arguments) که کارایی ِ مشابهی با options objects دارند.

چه زمانی باید از option objectها استفاده کرد؟

زمانی که تابعی حداقل دو یا بیشتر آرگومان داشته باشد، می‌توان استفاده از options object را مد ِ نظر قرار داد. برای تابعی که چهار یا بیشتر آرگومان دارد، استفاده از options object معمولاً ایده‌ی خوبی است.

اگر تابعی فعلا یک آرگومان بیشتر ندارد، اما حدس می‌زنید که بعدا نیاز خواهد شد تا آرگومان‌های بیشتری به آن اضافه کنید، از همان ابتدا از options object استفاده کنید تا نیاز نباشد بعدا کد‌های خود را از نو بنویسید.

در نهایت آنچه که تعیین کننده‌ی این است که آیا options object گزینه‌ی بهتری است یا لیست آرگومان‌ها (یعنی همان روش ِ معمول برای ِ دادن ِ ورودی به توابع)، این است که آیا پاسخ به پرسش ِ «آرگومان‌ها برای چه هستند» واضح است یا نه. برای مثال ورودی‌های تابع (sum(4, 2 به قدر  ِ کافی گویا هستند، اما چیزی مثل (showDialog(true , false خیر.

نوشتن ِ یک تابع که ورودی ِ آن یک options object است

در زیر یک تابع را مشاهده می‌کنید که به روش ِ سنتی ِ گرفتن ِ آرگومان‌ها به صورتِ جدا جدا، نوشته شده است:

function showDialog (showAlertIcon, showBackdrop) {
    if (showAlertIcon) {
        alertIcon.show();
    }
    if (showDarkBackdrop) {
        backdrop.show();
    }
    dialog.show();
}

و در ادامه نحوه‌ی فراخوانی ِ آن:

showDialog(true, false);

خط ِ بالا به وضوح مشخص نمی‌کند که هر آرگومان برای چه کاری است. این مشکل با از نو نوشتن ِ تابع، به صورتی که یک options object را به عنوان ِ ورودی بگیرد، حل می‌شود:

function showDialog (options) {
    if (options.showAlertIcon) {
        alertIcon.show();
    }
    if (options.showDarkBackdrop) {
        backdrop.show();
    }
    dialog.show();
}

حال، showDialog می‌تواند با یک شیء به عنوان ِ ورودی فراخوانی شود؛ که در آن شیء به ازای ِ هر پارامتر، یک جفت ِ کلید/مقدار (به انگلیسی: key/value) وجود دارد:

showDialog({
    showAlertIcon: true,
    showDarkBackdrop: false
});

با این روش، به روشنی مشخص است که هر پارامتر ِ تابع برای چه کاری است و نیازی به نگاه انداختن به تعریف ِ تابع، برای ِ درک ِ نحوه‌ی ِ فراخوانی ِ تابع نیست.

تنظیم مقادیر اولیه

options objectها همچنین امکان ِ اختیاری کردن ِ یک پارامتر را به راحتی می‌دهند. زمانیکه یک پارامتر ِ اختیاری، مقداردهی نشده، یک مقدار ِ اولیه باید جای ِ آن را بگیرد.

کتابخانه‌ی Underscore متدی با نام ِ defaults._ دارد که options object داده شده را مستقیما تغییر می‌دهد؛ بنابراین بهتر است برای ِ عدم ِ پیش‌آمدن ِ نتایج ناخواسته، از استفاده از این متد به طور ِ مستقیم خودداری کنید.

به جای ِ آن می‌توانید یک تابع ِ مخصوص ِ خودتان بنویسید:

function setDefaults(options, defaults){
    return _.defaults({}, _.clone(options), defaults);
}

تابع ِ setDefaults یک کپی از آرگومان ِ options که به آن داده شده، می‌سازد؛ که با این کار تضمین می‌کند که options object اصلی بدون ِ تغییر خواهد‌ماند.

حالا می‌توانید از setDefaults برای ِ مقداری‌دهی ِ اولیه‌ی پارامتر ِ داده شده به تابعتان استفاده‌کنید.

  function showDialog (options) {
      var defaults = {
          showAlertIcon: false,
          showDarkBackdrop: true
      };
      options = setDefaults(options, defaults);
      if (options.showAlertIcon) {
          alertIcon.show();
      }
      if (options.showDarkBackdrop) {
          backdrop.show();
      }
      dialog.show();
  }

بعد از این تغییر می‌توانید تابع ِ showDialog را تنها با پارامتر‌هایی که می‌خواهید صدابزنید:

  showDialog({showDarkBackdrop: false});

 

منبع: http://www.codereadability.com/what-are-javascript-options-objects/

جاوااسکریپت: بررسی ِ این که آیا یک متغیر تعریف شده است یا نه

در جاوااسکریپت یک متغیر تعریف شده است «اگر و فقط اگر» حین ِ دسترسی به آن خطای ِ ReferenceError تولید نشود.

راه ِ معمولی که خیلی‌ها برای ِ بررسی ِ تعریف شده بودن ِ یک متغیر استفاده می‌کنن، به شکل ِ زیر است:

typeof variableName !== 'undefined'

عبارت ِ بولین ِ بالا در دو حالت مقدار ِ false خواهد داشت:

  • متغیر ِ مورد ِ نظر در scope وجود نداشته باشد
  • متغیر ِ مورد ِ نظر وجود داشته باشد و مقدار آن undefined باشد

در غیر ِ این صورت عبارت، مقدار ِ true را برمی‌گرداند.

اما راه ِ مطمئن، درست و البته کمی پردردسر ِ این مشکل، این است که تلاش کنیم تا به متغیر دسترسی پیدا کنیم و سپس اگر خطای ِ RefrenceError تولید شد، آن را catch کنیم و از این طریق بفهمیم که متغیر تعریف شده یا نه:

var barIsDeclared = true; 
try { bar; }
catch (e) {
    if (e.name === "ReferenceError") {
        barIsDeclared = false;
    }
}

منبع: https://stackoverflow.com/questions/16719277/checking-if-a-variable-exists-in-javascript

جاوا‌اسکریپت: بررسی وجود یک ویژگی در شئ

برای این کار سه روش معمول وجود داره که به ترتیب اونارو بررسی می‌کنیم:

روش خسته: استفاده از خاصیت undefined

انجام این کار به لطف یک رفتار خاص و البته جالب جاوا‌اسکریپت خیلی راحت انجام می‌شه: اگه یک ویژگی در شیئ موجود نباشه، مقدار undefined برای اون بر‌می‌گرده. مثلا:

const objA = {
  propA: 'A property!',
  propB: 'B property!',
};

console.log(typeof objA.propA); // prints 'string'
console.log(typeof objA.propC); // prints 'undefined'


function fA (obj) {
  // هست propFooBar اگه شیئ دارای ویژگی
  if (obj.propFooBar === undefined) // Or: typeof obj.propFooBar === 'undefined'
    console.log(obj.propFooBar);
  else
    console.log('Object does not have propFooBar');
}

fA({propSilly: "I am silly!"}); // prints 'Object does not have propFooBar'
fA({propFooBar: "I am here!"}); // prints 'I am here!'

از اونجا که در جاوا‌اسکریپت undefined وقتی به یک مقدار بولین (Boolean) تبدیل میشه معادل false میشه، شاید بعضیا تصور کنن به جای استفاده از اپراتور typeof یا مقایسه با undefined می‌تونن این کار رو انجام بدن:

const objA = {};
const objB = {propFooBar: false};

function fA (obj) {
  if (obj.propFooBar)
    console.log('Object has propFooBar');
  else
    console.log('Object does not have propFoobar');
}

/*
 * هردوی دستورات زیر خروجی دوم رو چاپ می‌کنن
 * رو ندارن propFooBar یعنی تابع فکر می‌کنه هردوی این اشیاء ویژگی 
 * در صورتی‌که شئ دوم این ویژگی رو داره
 */
fA(objA);
fA(objB);

اما این کار اشتباهه چون اگه حتی propFooBar در شئ تعریف شده باشه و مثلا مقدارش false یا null باشه بازهم به این تعبیر می‌شه که این ویژگی تعریف نشده و می‌تونه برنامه رو با خطا مواجه کنه.

حالا چرا گفتیم این ویژگی خاصه؟ چون در اکثر زبان‌ها (مثل پایتون)، وقتی می‌خوایم به یک ویژگی از شئ که اون ویژگی موجود نیست، دسترسی پیدا کنیم، با خطا مواجه می‌شیم. یعنی برای بررسی وجود یک ویژگی در شئ باید یک بلوک try…catch بنویسیم یا از توابع و امکانات خاصی که در اون زبان وجود داره استفاده کنیم (مثلا در پایتون میشه از تابع hasattr استفاده کرد). اما توجه کنید که این ویژگی در جاوا‌اسکریپت یه چاقوی دو لبس و اگه حواسمون نباشه می‌تونه آسیب بزنه!

روش دوم: استفاده از hasOwnProperty

بیاین شیئ زیر رو در نظر بگیریم:

const objC = {
  propA: undefined,
};

در objC ویژگی propA تعریف شده ولی صریحا مقدار undefined به اون داده شده! احتمالا می‌تونید حدس بزنید که اگه بخوایم با استفاده از روش قبلی بررسی کنیم که آیا این شئ ویژگی propA رو داره یا نه به اشتباه فکر خواهیم کرد که این ویژگی روی شئ تعریف نشده، در صورتیکه اینطور نیست! پس باید چیکار کرد؟ باید دست به دامن ابزار‌های خاصی شد که جاوا‌اسکریپت برامون فراهم کرده. ادامه مطلب

ترفند پایتونی: بروزرسانی پکیج‌هاي pip در اوبونتو

متاسفانه هنوز دستوری برای بروزرسانی تمام بسته‌های pip وجود نداره؛ و برای این کار باید هر بسته رو جداگونه بروزرسانی کرد. (گرچه این امکان به عنوان یه درخواست برای تیم توسعه pip در حال بررسیه و شاید بزودی به pip اضافه بشه)

دستوری که من برای این کار (در اوبونتو) ازش استفاده می‌کنم و ممکنه به درد شما هم بخوره، این دستوره: (برای python3)

pip3 list --outdated | cut -d ' ' -f 1 | xargs -n1 pip3 install -U --user

و برای python2:

pip list --outdated | cut -d ' ' -f 1 | xargs -n1 pip install -U --user

اگه می‌خواید بسته‌ها به جای user برای کل سیستم نصب بشن کافیه این تغییرات رو بدید : (برای python2 به جای pip3 از pip استفاده کنید)

pip3 list --outdated | cut -d ' ' -f 1 | xargs -n1 sudo pip3 install -U

اگه نسخه‌ای از pip رو استفاده می‌کنید که از دستور pip3 list –outdated پشتیبانی نمی‌کنه، این لینک ممکنه بدردتون بخوره.

و اگه علاقه‌مندید بدونید این دستور چطوری کار می‌کنه، فهمیدن طرز کار دستورات cut و xargs و مفهوم pipeline در لینوکس می‌تونه کمکتون کنه.

اگه ترفند مرتبطی بلدید و یا پیشنهادی دارید، در پایین پست دیدگاهتون رو با بقیه سهیم بشید 🙂

ترفند پایتونی: پیاده‌سازی آسون توابع مقایسه‌ای

انواع اپراتور‌های مقایسه‌ای در پایتون و تابع مربوط به اونا برای پیاده‌سازیشون در کلاسها به شرح زیر هستن:

  • <           __gt__
  • >           __lt__
  • ==        __eq__
  • =!         __ne__
  • =<        __ge__
  • =>        __le__

فرض کنید می‌خوایم مفهوم خط هندسی رو در قالب یه کلاس پیاده‌سازی کنیم:

from math import sqrt


class Line:
    """
    پیاده سازی خط هندسی
    """
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def length(self):
        """
       محاسبه طول خط
        """
        return sqrt(self.x**2 + self.y**2)

حالا فرض کنید دو تا شیئ از این کلاس درست می‌کنیم و بعد از اون، طول این خط‌ها را که در قالب کلاس Line تعریف شدن، باهم مقایسه می‌کنیم:

l1 = Line(1, 2)
l2 = Line(-3, -4)

if l1 < l2:
    print('اولی کوچیکتره')

اگه کد بالا رو اجرا کنیم با خطای ()TypeError: unorderable types: Line() < Line مواجه می‌شیم. این خطا داره بهمون میگه که اپراتور کوچکتر از برای این کلاس تعریف نشده. پس نیاز داریم تا اول این اپراتور رو تعریف کنیم:

from math import sqrt


class Line:
    """
    پیاده سازی خط هندسی
    """
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def length(self):
        """
        محاسبه طول خط
        """
        return sqrt(self.x**2 + self.y**2)
        
    def __lt__(self, other):
        """
        < سربارگذاری عملگر
        """
        return self.length() < other.length()

می‌بینید که برای کلاس Line مفهوم کوچکتر بودن رو این معنا کردیم که طول خط یکی، کوچتر از دیگری باشه. مثلا اگه به جای خط قرار بود کلاس Person (اطلاعات یک شخص) رو پیاده‌سازی کنیم ممکن بود مفهوم کوچتر بودن رو، کوچکتر بودنِ سن یک فرد نسبت به دیگری معنا می‌کردیم.
بعد از تعریف این متد، دیگه به راحتی می‌تونیم دو شیئ از کلاس Line رو با عملگر > باهم مقایسه کنیم.

اما بقیه عملگرها چی؟ هنوز ۵ تای دیگه باقی موندن!

نکتهاپراتور‌های زیر دو به دو همدیگه رو انعکاس میدن؛ به این معنا که اگه یکی رو پیاده سازی کنیم و دیگری رو پیاده‌سازی نکنیم، اپراتور دیگری اتوماتیک پیاده‌سازی خواهد شد:

  • >     و    <
  • ==   و    =!
  • =>   و    =<

یعنی برای پیاده‌سازی هر شش عملگر باید حداقل سه تای اونارو پیاده‌سازی کنیم. که اگه کلاسمون بزرگ باشه، این کار برامون خسته‌کننده می‌شه.

اما می‌رسیم به قسمت خوب ماجرا؛ تابع total_ordering در ماژول functools.
در مستندات این تابع اینطور نوشته که تنها کافیه یکی از توابع __lt__، __gt__، __le__ یا __gt__ به همراه تابع __eq__ رو برای کلاسمون تعریف کنیم و کلاس رو با تابع total_ordering دکور کنیم! بعدش خیلی راحت کلاسمون هر شش تابع مقایسه‌ای رو خواهد داشت. مثال:

from math import sqrt
from functools import total_ordering


@total_ordering
class Line:
    """
    پیاده سازی خط هندسی
    """
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def length(self):
        """
        محاسبه طول خط
        """
        return sqrt(self.x**2 + self.y**2)
    
    def __eq__(self, other):
        """
        == سربارگذاری عملگر 
        """
        return self.length() == other.length()
        
    def __lt__(self, other):
        """
        < سربارگذاری عملگر 
        """
        return self.length() < other.length()

 

البته ناگفته نمونه که اگه برای برنامه شما سرعت خیلی حیاتیه، بهتره توابع مقایسه‌ای رو خودتون و به صورت دستی پیاده‌سازی کنید؛ چون استفاده از این روش نسبت به پیاده‌سازی دستی کندتره.

اگه اشکالی در جایی از متن پیدا کردید و یا پیشنهادی داشتید، ممنون می‌شم تا پایین پست، دیدگاهتون رو با بقیه در‌میون بذارید 🙂

args* و kwargs** در پایتون

args* به ما این امکان رو میده که به جای تعداد ثابتی ورودی یه تابع بتونه تعداد متغیری ورودی بگیره. برای مثال تابع زیر رو در نظر بگیرید:

def my_sum(a, b):
    return a + b

my_sum(2, 3) # 5

این تابع دو تا عدد رو باهم جمع می‌کنه و همیشه دو تا ورودی می‌گیره و اگه بیشتر یا کمتر ورودی بهش بدیم با خطا مواجه می‌شیم.
فرض کنید به جای دو عدد میخوایم چندتا عدد (که ممکنه در هر بار فراخوانی تابع تعدادشون فرق کنه) رو با هم جمع کنیم. یه راه اینه که تابعمون یه ورودی list بگیره و اعداد توی لیست رو با هم جمع کنه. برای مثال:

def sum_list(nums):
    sum = 0
    for num in nums:
        sum += num
    return sum

sum_list([2, 3]) # 5
sum_list([2, 3, 5, 8]) # 18

اما راه دیگه اینه که به جای قرار دادن عددهامون توی یه لیست، اونارو مستقیم و به شکل آرگومان به تابعمون بدیم:

def my_sum(*nums):
    sum = 0
    for num in nums:
        sum += num
    return sum
    
my_sum(2, 3) # 5
my_sum(2, 3, 5, 8) # 18

ادامه مطلب

فشرده‌سازی تصاویر JPEG با خط فرمان لینوکس

قانون نانوشته‌ای هست که میگه برای انجام هرکاری یه روش به سبک ترمینال لینوکسی وجود داره! فشرده‌سازی تصاویر JPEG هم از این قاعده مستثنی نیست.

با افزایش کیفیتِ دوربینِ گجت‌های تکنولوژیِ مختلف، خیلی اوقات نیاز داریم تا کیفیت عکس‌هایی که با این وسایل گرفتیمو کاهش بدیم؛ حالا چه این نیاز بخاطر ارسال راحتتر اون تصویر به دوستا و آشنا‌هامون باشه چه بخاطر محدودیت یه سایت برای آپلود تصویر پروفایل.
در این شرایط اولین کاری که انجام میدیم یه جستجوی سادس تو گوگل. و احتمالا می‌گردیم دنبال یه راه‌کار آنلاین! به طور مثال یه سایت که عکسمونو اونجا آپلود کنیم و بعد از این که سایت عکس رو فشرده کرد دوباره اونو دانلود کنیم.
برای یکی دو تا عکسِ نه چندان حجیم راهکار خوبی به نظر میاد اما اگه قرار باشه تعداد زیادی عکسِ با کیفیت خیلی بالا رو فشرده کنید منطقی‌تره که دنبال یه ابزار آفلاین بگردید.
در اینجا دوباره انتخاب با شماست که برید سراغ یه ابزار گرفیکی یا این که خط فرمانِ شیرینِ لینوکوسو انتخاب کنید! اگه انتخابتون گزینه‌ی آخره در ادامه با ما همراه باشید.

ادامه مطلب