Python is widely known for its simplicity, easy syntax, which requires basic English to understand, which made it so famous.
The simplicity of Python is what makes it so appealing for beginners, no declaration, without fancy words, or weird syntax. It continues with cools features, like decorators, and list comprehensions that do work wonders, but the *(asterisk) deserves the same spot, and I’m here to show you why.
Getting the ball rolling
I’ll start with a small trick:
Easy Way To Combine Dicts!
Now as you can easily see, I just concatenated to dictionaries with just a few asterisks, I’m going to explain everything, but I just wanted to show you what you have been missing so far!
Where Does the Astrix do?
Besides its well know usage for multiplication, the Astrix lets you do something pretty significant (and convenient) called unpacking.
You can use asterisks to unpack an iterable, and double unpack if it’s a two way iterable (like a dictionary).
The Power Of Unpacking
Don’t Break Someone Else’s Code
This usage is more commonly known, but still underused.
Every time a developer writes a function, the function has a signature. If the function changes, every piece of code written by someone else based on your code, will break.
Args and Kwargs is a simple method to add functionality to your functions, without breaking its backward compatibility, resulting in more modular code. Your function receive *args, **kwargs
as an input, which unpacks the entire extra input into the function. Single Astrix is for standard iterable, double Astrix is for dictionary type, as always — an example:
working code and breaking code
This Example demonstrates how you can use args and kwargs to receive future arguments, for future use, without breaking old calls to your functions, this is super important!
if you have some spare read time — id recommend you’ll read this:
The Astrix is a significant part of Python and doesn’t get the honor and reputation it deserves. I hope this article helped even just a bit to change it. If you found this interesting, or have a topic you wish to read about, please do comment. I Hope You Enjoyed It!
때때로 우리는 데이터 세트에서 일부 데이터가 누락 된 것을 발견합니다. 누락 된 값은 성능 매트릭스 및 예측의 품질을 저하 시키므로 신중하게 처리해야합니다. 어떤 모델도 이러한 NULL 또는 NaN 값을 자체적으로 처리 할 수 없으므로 처리해야합니다. 먼저 데이터 세트에 null 값이 있는지 여부를 확인해야합니다. isnull () 메소드를 사용하여이를 수행 할 수 있습니다.
누락 된 값을 처리하는 방법에 대한 올바른 결정을 내리면 강력한 데이터 모델이 생성되므로 분석가가 직면 한 가장 큰 문제 중 하나입니다. 결 측값을 대치하는 다양한 방법을 살펴 보겠습니다.
행 삭제
가장 일반적으로 사용되는 방법입니다. null 값이있는 행과 누락 된 값의 60 % 이상이있는 경우 특정 열을 삭제합니다. 이 방법은 해당 열이 해당 특성이 모델 예측에 대해 덜 중요하거나 중요하지 않은 모델의 예측에 영향을 미치지 않는 경우에만 사용됩니다.
평균 / 중앙값 / 모드로 바꾸기
이 방법은 수치 데이터로 구성된 기능에 적용 할 수 있습니다. 특성의 평균, 중앙값 또는 최빈값을 계산하고이를 누락 된 값으로 바꿀 수 있습니다. 이 방법은 행과 열을 제거하는 것에 비해 더 나은 결과를 제공합니다.
범주 형 데이터 처리
때때로 우리의 데이터는 텍스트 형식입니다. 텍스트 형식으로 카테고리를 찾을 수 있습니다. 모델이 수학 방정식과 계산을 기반으로하기 때문에 기계가 텍스트를 이해하고 처리하는 것은 복잡해집니다. 따라서 데이터를 숫자로 인코딩해야합니다.
이를 위해 우리는scikit-learn의 LabelEncoder작업에 사용할.해당 클래스의 객체를 생성합니다. 객체 labelencoder_X를 호출합니다.fit_transformLabelEncoder 클래스의 메서드가 도움이 될 것입니다.
이제 텍스트가 숫자로 대체되었습니다. 카테고리가 세 개 이상인 경우 다른 카테고리에 정수를 계속 할당하여 혼란을 유발합니다. 4 개의 범주가 있고 첫 번째 범주에 0을 할당하고 마지막 범주에 3을 할당한다고 가정합니다. 그러나 1은 0보다 크고 3은 1보다 크기 때문에 모델의 방정식은 3이 0보다 우선 순위가 가장 높다고 생각합니다. 이 문제를 해결하기 위해 n 개의 범주에 대해 n 개의 열이있는 더미 변수를 사용합니다.OneHotEncoder.
우리는 다른 클래스를 가져올 것입니다scikit의 OneHotEncoder가 학습합니다.우리는 해당 클래스의 객체를 생성하고 열의 인덱스 값을 취하고 OneHotEncoding에도 fit_transform ()을 사용하는 categorical_features라는 매개 변수를 고려할 것입니다.
ColumnTransformer를 사용하면 입력을 별도로 변환하고 생성 된 기능을 연결하여 단일 공간을 형성 할 수 있습니다. 이기종 데이터 변환에 유용합니다.
기능 확장
독립 변수의 값을 표준화하는 데 사용됩니다. 변수의 범위를 제한하여 쉽게 비교할 수 있도록하는 방법입니다.
왜 필요한가요?
대부분의 기계 학습 모델은 유클리드 거리를 기반으로합니다. 훨씬 큰 값에 비해 낮은 값의 제곱 차이는 거의 존재하지 않는 것처럼 처리됩니다. 우리는 그런 일이 일어나기를 원하지 않습니다. 그렇기 때문에 모든 변수를 동일한 척도로 변환해야합니다.
대부분의 기계 학습 모델은 유클리드 거리를 기반으로합니다. (x2-x1)의 제곱근 값이 (y2-y1)보다 크면 (y2-y1)은 무시됩니다. 우리는 이런 일이 일어나기를 원하지 않습니다. 그렇기 때문에 모든 변수를 동일한 척도로 변환해야합니다. 이를 수행 할 수있는 두 가지 방법이 있습니다.
표준화
정규화를 통해 0.0에서 1.0 사이의 특성 값을 조정합니다.
표준화
평균이 0이고 표준 편차가 1이되도록 특성을 확장합니다.
scikit 전처리 라이브러리에서 StandardScaler를 가져 와서 해당 클래스의 객체를 만들어야합니다.
이제 X_train 세트를 맞추고 변형 할 때입니다. 훈련 및 테스트 세트에 표준 스케일러를 적용 할 때. 훈련 세트에만 맞추고 변환해야합니다. 테스트 세트의 경우 변환해야합니다. 테스트 세트에 맞출 필요가 없습니다. 이렇게하면 모든 값이 표준화 된 척도로 변환됩니다.
제 기사를 읽어 주셔서 감사합니다. 여러분의 의견을 듣게되어 기쁩니다. 최신 기사에 대한 업데이트를 받으려면 Medium에서 저를 팔로우하십시오. 당신은 또한 나와 연결할 수 있습니다Linkedin과트위터.Machine Learning 및 Deep Learning에 대한 내 블로그를 확인하십시오.
Considering the fact that high-quality data leads to better predictions, data preprocessing has become a fundamental step in data science and machine learning. We’ll talk about the importance of processing data and discuss different approaches in sequence.
What is Data PreProcessing
It is a technique that transforms raw data into an understandable format. Real-world data(raw data) is always incomplete and that data cannot be sent through models as it would cause certain errors. That is why we need to preprocess data before sending it through a model.
Here are the steps I have followed;
Import libraries
Read the Dataset
Split the dataset into independent and dependent
Handling missing values
Handling categorical values
Standardization/ Feature Scaling
Step 1: Import Libraries
The first step is usually importing the libraries that will be needed in the program. A library is essentially a collection of modules that can be called and used. Here we will be using
Pandas: We use pandas for data manipulation and data analysis. Numpy: It is a fundamental package for scientific computing with Python.
Step 2: Import the Dataset
Most of the dataset’s come in .csv(comma-separated value) format. It’s important to keep the dataset in the same folder as your program and read it using a method called read_csv which can be found in the library called pandas.
Step 3: Split the data into independent and dependent features
We will create a matrix of features in our dataset by creating an Independent variable(X) and a dependent variable (Y).To read the columns, we will use iloc of pandas which takes two parameters — [row selection, column selection].
: as a parameter, it selects all rows in the data. For columns, we have -1, which means all the columns will be selected except for the last one.
Sometimes we find some data is missing in the dataset. Missing values need to be handled carefully because they reduce the quality of any of our performance matrix and prediction. No model can handle these NULL or NaN values on its own so we need to deal with it. Firstly, we need to check whether we have null values in our dataset or not. We can do that using the isnull() method.
Handling the missing values is one of the greatest challenges faced by analysts because making the right decision on how to handle it generates robust data models. Let us look at different ways of imputing the missing values.
Deleting Rows
This is the most commonly used method. We either delete a row which has null values and a particular column if it has more than 60% of missing values. This method is only used when that column does not affect the model's prediction that is that feature has less significance or no significance for predicting the model.
Replacing With Mean/Median/Mode
This method can be applied to the features which consist of numerical data. We can calculate the mean, median, or mode of the feature and replace it with the missing values. This method gives better results compared to the removal of rows and columns.
Handling Categorical Data
Sometimes our data is in text form. We can find categories in text form. It gets complicated for machines to understand texts and process them since the models are based on mathematical equations and calculations. Therefore we need to encode the data into numbers.
To make this happen we import a library called LabelEncoder from scikit-learn which we will use for the task. We will create an object of that class. We will call our object labelencoder_X. fit_transform method in the LabelEncoder class will help us.
Now, the text has been replaced by numbers, what if there are more than two categories we keep assigning integers to different categories which lead to confusion. Suppose we have four categories and we assign the first category with 0 and the last category with 3. However, since 1 is greater than 0 and 3is greater than 1 the equations in the model we think 3 has the highest priority than 0. In order to resolve this problem, we use dummy variables where we will have n number of columns for n categories for that we make use of OneHotEncoder.
We will import another class called OneHotEncoder from scikit learn. we will create an object of that class and consider a parameter called categorical_features which takes a value of the index of the column and use fit_transform() for OneHotEncoding as well.
ColumnTransformer allows the input to be transformed separately and the features generated are concatenated to form a single space. It is useful for a heterogeneous data transformations
Feature Scaling
It is used to standardize the values of Independent variables. It is a method used to limit the range of variables so that they can be easily compared.
Why is it necessary?
Most of the machine learning models are based on Euclidean distances. The square difference with the lower value in comparison to the far greater value will almost be treated as if it does not exist. We do not want that to happen. That is why it is necessary to transform all our variables into the same scale.
Most of the Machine Learning models are based on Euclidean distances. Consider if the square root value of (x2-x1) is greater than (y2-y1), then (y2-y1) will be neglected. We don’t want this to happen. That is why it is necessary to transform all our variables into the same scale. There are two ways you can do this.
Normalization
With the help of Normalization, we scale the feature values in between 0.0 and 1.0
Standardization
It scales features to have a mean of zero and a standard deviation one.
we need to import StandardScaler from the scikit preprocessing library and create an object of that class.
It’s time to fit and transform our X_train set. When we apply Standard Scaler to our training and testing sets. We need to fit and transform only to the training set, In case of the test set, we need to transform, no need to fit it to the test set. This will transform all the values to a standardized scale.
Thank you for reading my article. I will be happy to hear your opinions. Follow me on Medium to get updated on my latest articles. You can also connect with me on Linkedin and Twitter. Check out my blogs on Machine Learning and Deep Learning.
핵심에서 Python은 객체 지향 프로그래밍 (OOP) 언어입니다. OOP 언어이기 때문에 Python은 객체 중심의 다양한 기능을 지원하여 데이터와 기능을 처리합니다. 예를 들어 데이터 구조는 일부 다른 언어에서 객체로 간주되지 않는 기본 유형 (예 : 정수 및 문자열)을 포함한 모든 객체입니다. 또 다른 예로, 함수는 모든 객체이며, 정의 된 다른 객체 (예 : 클래스 또는 모듈)의 속성 일뿐입니다.
기본 제공 데이터 유형을 사용하고 사용자 지정 클래스를 만들지 않고도 여러 함수를 작성할 수 있지만 프로젝트 범위가 커지면 코드를 유지 관리하기가 더 어려워 질 수 있습니다. 이러한 개별 부분에는 공유 된 테마가 없으며 많은 정보가 관련되어 있지만 이들 간의 연결을 관리하는 데 많은 번거 로움이 있습니다.
이러한 시나리오에서는 관련 정보를 그룹화하고 프로젝트의 구조 설계를 개선 할 수 있도록 고유 한 클래스를 정의하는 것이 좋습니다. 더 중요한 것은 코드 조각이 덜 조각 된 코드를 다루게되므로 코드베이스의 장기적인 유지 관리 가능성이 향상된다는 것입니다. 그러나 한 가지 문제가 있습니다. 이것은 사용자 정의 클래스를 정의하는 이점이 관리 오버 헤드보다 클 수 있도록 클래스 선언이 올바른 방식으로 수행 된 경우에만 해당됩니다.
이 기사에서는 사용자 정의 클래스에 적용 할 수있는 9 가지 중요한 모범 사례를 검토하고자합니다.
1. 좋은 이름
자신 만의 클래스를 정의 할 때 코드베이스에 새로운 아기를 추가하는 것입니다. 수업에 아주 좋은 이름을 지정해야합니다. 클래스 이름의 유일한 제한은 합법적 인 Python 변수의 규칙 (예 : 숫자로 시작할 수 없음)이지만 클래스 이름을 지정하는 데 선호되는 방법이 있습니다.
발음하기 쉬운 명사를 사용하십시오.팀 프로젝트에서 작업하는 경우 특히 중요합니다. 그룹 프레젠테이션 중에 "이 경우에는 Zgnehst 클래스의 인스턴스를 만듭니다."라고 말하는 사람이되고 싶지 않을 것입니다. 또한 발음하기 쉽다는 것은 이름이 너무 길어서는 안된다는 의미이기도합니다. 클래스 이름을 정의하기 위해 3 개 이상의 단어를 사용해야하는 경우는 거의 생각할 수 없습니다. 한 단어가 가장 좋고 두 단어가 좋고 세 단어가 한계입니다.
저장된 데이터와 의도 한 기능을 반영합니다.마치 우리의 실제 생활과 같습니다. 소년에게는 소년 이름이 주어집니다. 남자 아이 이름을 보면 아이들이 남자 일 것으로 예상합니다. 클래스 이름 (또는 일반적으로 다른 변수)에도 적용됩니다. 규칙은 간단합니다— 사람들을 놀라게하지 마십시오. 학생의 정보를 다루는 경우 수업 이름은 Student로 지정해야합니다. KiddosAtCampus는 가장 상식적인 말이 아닙니다.
명명 규칙을 따르십시오.GoodName과 같은 클래스 이름에는 대문자 낙타 스타일을 사용해야합니다. 다음은 goodName, Good_Name, good_name 및 GOodnAme와 같은 비 전통적인 클래스 이름의 불완전한 목록입니다. 명명 규칙을 따르는 것은 의도를 명확하게하는 것입니다. 사람들이 코드를 읽을 때 GoodName과 같은 이름을 가진 객체가 클래스라고 안전하게 가정 할 수 있습니다.
속성 및 함수에 적용되는 명명 규칙 및 규칙도 있습니다. 아래 섹션에서 해당되는 경우 간략하게 언급하지만 전체 원칙은 동일합니다. 유일한 경험 법칙은 간단합니다. 사람들을 놀라게하지 마십시오.
2. 명시 적 인스턴스 속성
대부분의 경우 자체 인스턴스 초기화 방법 (예 :__init__). 이 메서드에서는 새로 생성 된 클래스 인스턴스의 초기 상태를 설정합니다. 하지만 Python은 커스텀 클래스로 인스턴스 속성을 정의 할 수있는 위치를 제한하지 않습니다. 즉, 인스턴스가 생성 된 후 이후 작업에서 추가 인스턴스 속성을 정의 할 수 있습니다. 다음 코드는 가능한 시나리오를 보여줍니다.
초기화 방법
위와 같이 인스턴스를 만들 수 있습니다.학생학생의 이름과 성을 지정하여 수업. 나중에 인스턴스 메서드를 호출 할 때 (즉,verify_registration_status),학생인스턴스의 상태 속성이 설정됩니다. 그러나 이것은 원하는 패턴이 아닙니다. 전체 클래스에 다양한 인스턴스 속성을 분산하면 인스턴스 객체가 어떤 데이터를 보유하고 있는지 클래스가 명확하게 할 수 없기 때문입니다. 따라서 모범 사례는 인스턴스의 속성을__init__메소드를 사용하면 아래와 같이 코드 리더가 클래스의 데이터 구조를 알 수있는 단일 위치를 갖게됩니다.
더 나은 초기화 방법
처음에 설정할 수없는 인스턴스 속성의 경우 다음과 같은 자리 표시 자 값으로 설정할 수 있습니다.없음. 그다지 문제가되지 않지만이 변경 사항은 일부 인스턴스 메서드를 호출하여 해당 인스턴스 속성을 설정하는 것을 잊었을 때 발생할 수있는 오류를 방지하는데도 도움이됩니다.AttributeError(‘학생’개체에‘status_verified’속성이 없습니다.).
이름 지정 규칙과 관련하여 속성은 소문자를 사용하여 이름을 지정하고 뱀 케이스 스타일을 따라야합니다. 즉, 여러 단어를 사용하는 경우 밑줄로 연결해야합니다. 또한 모든 이름에는 보유한 데이터에 대한 의미있는 표시가 있어야합니다 (예 :이름~보다 낫다fn).
3. 속성 사용-그러나 간결하게
어떤 사람들은 자바와 같은 다른 OOP 언어의 기존 배경으로 Python 코딩을 배우고 인스턴스 속성에 대한 getter 및 setter를 만드는 데 사용됩니다. 이 패턴은 Python에서 속성 데코레이터를 사용하여 모방 할 수 있습니다. 다음 코드는 속성 데코레이터를 사용하여 getter 및 setter를 구현하는 기본 형식을 보여줍니다.
부동산 데코레이터
이 속성이 생성되면 내부 함수를 사용하여 구현되지만 점 표기법을 사용하여 일반 속성으로 사용할 수 있습니다.
속성 사용
아시다시피 속성 구현을 사용하는 이점에는 적절한 값 설정 (정수가 아닌 문자열이 사용되는지 확인) 및 읽기 전용 액세스 (setter 메서드를 구현하지 않음)가 포함됩니다. 그러나 속성을 간결하게 사용해야합니다. 사용자 정의 클래스가 아래와 같이 보이면 매우 산만해질 수 있습니다. 속성이 너무 많습니다!
재산 남용
대부분의 경우 이러한 속성은 인스턴스 속성으로 대체 될 수 있으므로 이러한 속성에 액세스하여 직접 설정할 수 있습니다. 논의 된대로 속성 사용의 이점 (예 : 값 확인)에 대한 특정 요구 사항이없는 경우 속성을 사용하는 것이 Python에서 속성을 만드는 것보다 선호됩니다.
4. 의미있는 문자열 표현 정의
파이썬에서는 이름 앞뒤에 이중 밑줄이있는 함수를 특수 또는 매직 메서드라고하며 어떤 사람들은이를 dunder 메서드라고합니다. 그들은 다음을 포함하여 통역사의 기본 작업에 특별한 용도가 있습니다.__init__이전에 다룬 방법입니다. 두 가지 특별한 방법,__repr__과__str__는 사용자 정의 클래스의 적절한 문자열 표현을 만드는 데 필수적이며 코드 판독기에게 클래스에 대한보다 직관적 인 정보를 제공합니다.
그들 사이의 주요 차이점은__repr__메소드는 문자열을 정의합니다.이를 사용하여 다음을 호출하여 객체를 다시 만들 수 있습니다.eval (repr ( "repr")), 동안__str__메소드는 더 설명적이고 더 많은 사용자 정의를 허용하는 문자열을 정의합니다. 즉, 정의 된 문자열이__repr__방법은 개발자가 보는 동안__str__방법은 일반 사용자가 볼 수 있습니다. 다음은 예를 보여줍니다.
문자열 표현의 구현
양해 해주십시오.__repr__메서드 구현 (7 행), f- 문자열은!아르 자형올바른 형식의 문자열로 인스턴스를 구성하는 데 필요하기 때문에 따옴표로 이러한 문자열을 표시합니다. ! r 형식이 없으면 문자열은학생 (John, Smith)을 구성하는 올바른 방법이 아닙니다.학생예. 이러한 구현이 문자열을 어떻게 보여 주는지 살펴 보겠습니다. 특히__repr__대화 형 인터프리터에서 개체에 액세스 할 때 메서드가 호출되고__str__메서드는 개체를 인쇄 할 때 기본적으로 호출됩니다.
문자열 표현
5. 인스턴스, 클래스 및 정적 메서드
클래스에서 우리는 인스턴스, 클래스, 정적 메서드의 세 종류의 메서드를 정의 할 수 있습니다. 관심있는 기능에 어떤 방법을 사용해야하는지 고려해야합니다. 다음은 몇 가지 일반적인 지침입니다.
예를 들어 메서드가 개별 인스턴스 개체와 관련된 경우 인스턴스의 특정 속성에 액세스하거나 업데이트해야합니다.이 경우 인스턴스 메서드를 사용해야합니다. 이러한 메서드에는 다음과 같은 서명이 있습니다.def do_something (self) :, 여기서본인인수는 메서드를 호출하는 인스턴스 개체를 참조합니다. 에 대해 더 알고본인인수, 당신은 참조 할 수 있습니다내 이전 기사이 주제에.
메서드가 개별 인스턴스 개체와 관련이없는 경우 클래스 또는 정적 메서드 사용을 고려해야합니다. 두 방법 모두 적용 가능한 데코레이터로 쉽게 정의 할 수 있습니다.classmethod과staticmethod. 이 두 가지의 차이점은 클래스 메서드를 사용하면 클래스와 관련된 속성에 액세스하거나 업데이트 할 수 있지만 정적 메서드는 인스턴스 또는 클래스 자체와 독립적이라는 것입니다. 클래스 메서드의 일반적인 예는 편리한 인스턴스화 메서드를 제공하는 반면 정적 메서드는 단순히 유틸리티 함수일 수 있습니다. 다음 코드는 몇 가지 예를 보여줍니다.
다른 종류의 방법
비슷한 방식으로 클래스 속성을 만들 수도 있습니다. 앞에서 논의한 인스턴스 속성과 달리 클래스 속성은 모든 인스턴스 객체에서 공유되며 개별 인스턴스 객체와 독립적 인 일부 특성을 반영해야합니다.
6. 개인 속성을 사용한 캡슐화
프로젝트를위한 사용자 정의 클래스를 작성할 때 특히 다른 사람들이 클래스를 사용할 것으로 예상되는 경우 캡슐화를 고려해야합니다. 클래스의 기능이 커지면 일부 함수 또는 속성은 클래스 내의 데이터 처리에만 관련됩니다. 즉, 클래스 외부에서는 이러한 함수가 호출되지 않으며 클래스의 다른 사용자는 이러한 함수의 구현 세부 사항에 대해 신경 쓰지 않습니다. 이러한 시나리오에서는 캡슐화를 고려해야합니다.
캡슐화를 적용하는 한 가지 중요한 방법은 규칙에 따라 밑줄 또는 두 개의 밑줄을 접두사로 속성 및 함수에 추가하는 것입니다. 미묘한 차이점은 밑줄이있는 항목은보호, 두 개의 밑줄이있는 항목은은밀한, 생성 후 이름 변경이 포함됩니다. 이 두 범주를 구별하는 것은이 기사의 범위를 벗어납니다.내 이전 기사 중 하나그들을 덮었습니다.
본질적으로 속성과 함수의 이름을 이렇게 지정하면 IDE (예 : PyCharm과 같은 통합 개발 환경)에 실제 개인 속성이 존재하지 않더라도 클래스 외부에서 액세스하지 않을 것임을 알립니다. 파이썬. 즉, 우리가 선택하면 여전히 액세스 할 수 있습니다.
캡슐화
위의 코드는 캡슐화의 간단한 예를 보여줍니다. 학생의 경우 평균 GPA를 아는 데 관심이있을 수 있으며 다음을 사용하여 점수를 얻을 수 있습니다.get_mean_gpa방법. 사용자는 평균 GPA가 어떻게 계산되는지 알 필요가 없습니다. 따라서 함수 이름 앞에 밑줄을 추가하여 관련 방법을 보호 할 수 있습니다.
이 모범 사례의 핵심 사항은 사용자가 코드를 사용하는 데 필요한 최소한의 공용 API 만 노출한다는 것입니다. 내부적으로 만 사용되는 경우 보호 또는 개인 방법으로 만드십시오.
7. 별도의 우려 사항 및 분리
프로젝트를 개발하면서 더 많은 데이터를 처리하고 있다는 사실을 알게되었으며, 하나의 클래스를 고수하는 경우 클래스가 번거로울 수 있습니다. 예를 들어 계속하겠습니다.학생수업. 학생들이 학교에서 점심을 먹고 각자 식사 비용을 지불하는 데 사용할 수있는 식사 계정을 가지고 있다고 가정합니다. 이론적으로는 계정 관련 데이터 및 기능을 다룰 수 있습니다.학생아래와 같이 클래스.
혼합 기능
위의 코드는 계정 잔액을 확인하고 계정에 돈을로드하는 데 대한 의사 코드를 보여줍니다. 둘 다학생수업. 분실 된 카드 일시 중지, 계정 통합과 같이 계정과 관련 될 수있는 더 많은 작업이 있다고 상상해보십시오. 이러한 작업을 모두 구현하면학생클래스가 점점 커지면서 점차 유지하기가 더 어려워집니다. 대신 이러한 책임을 분리하고학생이러한 계정 관련 기능에 대해 무책임한 클래스 — 다음과 같은 디자인 패턴디커플링.
분리 된 우려
위의 코드는 추가로 데이터 구조를 설계하는 방법을 보여줍니다.계정수업. 보시다시피 모든 계정 관련 작업을계정수업. 학생의 계정 정보를 검색하려면학생클래스는 정보를 검색하여 기능을 처리합니다.계정수업. 클래스와 관련된 더 많은 기능을 구현하려면 간단히 업데이트 할 수 있습니다.계정수업 만.
디자인 패턴의 주요 요점은 개별 수업에 별도의 문제가 있기를 원한다는 것입니다. 이러한 책임을 분리하면 더 작은 코드 구성 요소를 다루게되므로 클래스가 더 작아지고 향후 변경이 더 쉬워집니다.
8. 최적화를 위해 __slots__ 고려
클래스가 데이터 만 저장하기위한 데이터 컨테이너로 주로 사용되는 경우__ 슬롯 __수업의 성능을 최적화합니다. 속성 액세스 속도를 높일뿐만 아니라 메모리도 절약하므로 수천 개 이상의 인스턴스 객체를 만들어야하는 경우 큰 이점이 될 수 있습니다. 그 이유는 일반 클래스의 경우 인스턴스 속성이 내부적으로 관리되는 사전을 통해 저장되기 때문입니다. 대조적으로,__ 슬롯 __, 인스턴스 속성은 내부적으로 C를 사용하여 구현 된 어레이 관련 데이터 구조를 사용하여 저장되며 성능은 훨씬 더 높은 효율성으로 최적화됩니다.
클래스 정의에서 __slots__ 사용
위의 코드는 우리가 어떻게 구현하는지에 대한 간단한 예를 보여줍니다.__ 슬롯 __수업에서. 특히 모든 속성을 시퀀스로 나열하면 더 빠른 액세스와 적은 메모리 소비를 위해 데이터 저장소에서 일대일 일치가 생성됩니다. 방금 언급했듯이 일반 클래스는 속성 액세스를 위해 사전을 사용하지만__ 슬롯 __구현되었습니다. 다음 코드는 그러한 사실을 보여줍니다.
__slots__ 클래스에 __dict__ 없음
사용에 대한 자세한 설명__ 슬롯 __에 대한 좋은 답변에서 찾을 수 있습니다.스택 오버플로, 그리고 당신은 공식에서 더 많은 정보를 찾을 수 있습니다선적 서류 비치. 더 빠른 액세스와 절약 된 메모리의 이점에 관해서는최근 매체 기사아주 좋은 시연이 있습니다. 여기에 대해 자세히 설명하지 않겠습니다. 그러나 한 가지 주목할 점은__ 슬롯 __부작용이 있습니다. 이는 추가 속성을 동적으로 생성하지 못하게합니다. 어떤 사람들은 클래스의 속성을 제어하는 메커니즘으로이를 제안하지만 디자인 방식이 아닙니다.
9. 문서
마지막으로, 수업 문서에 대해 이야기해야합니다. 가장 중요한 것은 문서 작성이 코드를 대체하는 것이 아니라는 점을 이해해야한다는 것입니다. 수많은 문서를 작성한다고해서 코드의 성능이 향상되는 것은 아니며 반드시 코드를 더 읽기 쉽게 만드는 것도 아닙니다. 코드를 명확히하기 위해 독 스트링에 의존해야하는 경우 코드에 문제가있을 가능성이 큽니다. 나는 당신의 코드가 그 자체로 모든 것을 말해야한다고 진정으로 믿습니다. 다음 코드는 일부 프로그래머가 할 수있는 실수를 보여줍니다. 불필요한 주석을 사용하여 잘못된 코드를 보완합니다 (즉,이 경우 의미없는 변수 이름). 반대로 좋은 이름을 가진 좋은 코드는 주석이 필요하지 않습니다.
잘못된 댓글 예
댓글과 독 스트링 작성에 반대한다는 말은 아니지만 실제로 사용 사례에 따라 다릅니다. 여러 사람이 코드를 사용하거나 두 번 이상 사용하는 경우 (예 : 코드에 액세스하는 유일한 사람이지만 여러 번) 좋은 댓글 작성을 고려해야합니다. 자신이나 팀원이 코드를 읽는 데 도움을 줄 수 있지만, 코드가 주석에서 말한대로 정확하게 작동한다고 가정해서는 안됩니다. 즉, 좋은 코드를 작성하는 것이 항상 명심해야 할 최우선 순위입니다.
최종 사용자가 코드의 특정 부분을 사용하는 경우 해당 사용자가 관련 코드베이스에 익숙하지 않기 때문에 독 스트링을 작성하는 것이 좋습니다. 그들이 알고 싶은 것은 관련 API를 사용하는 방법 뿐이며, docstring은 도움말 메뉴의 기초를 형성합니다. 따라서 프로그램 사용 방법에 대한 명확한 지침을 제공하는 것은 프로그래머의 책임입니다.
결론
이 기사에서는 자신의 클래스를 정의 할 때 고려해야 할 중요한 요소를 검토했습니다. Python이나 일반적인 프로그래밍을 처음 접한다면 지금까지 논의한 모든 측면을 완전히 이해하지 못할 수도 있습니다. 괜찮습니다. 더 많이 코딩할수록 클래스를 정의하기 전에 이러한 원칙을 염두에 두는 것의 중요성을 더 많이 알게 될 것입니다. 좋은 디자인은 나중에 개발 시간을 많이 절약 할 수 있기 때문에 클래스 작업을 할 때 이러한 지침을 계속해서 연습하십시오.
At its core, Python is an object-oriented programming (OOP) language. Being an OOP language, Python handles data and functionalities by supporting various features centered around objects. For instance, data structures are all objects, including primitive types (e.g., integers and strings) which aren’t considered objects in some other languages. For another instance, functions are all objects, and they are merely attributes of other objects where they are defined (e.g., class or module).
Although you can use built-in data types and write a bunch of functions without creating any custom classes, chances are that your code can become harder and harder to maintain when the project’s scope grows. These separate pieces have no shared themes, and there will be lots of hassles to manage connections between them, although much of the information is related.
In these scenarios, it’s worth defining your own classes, which will allow you to group related information and improve the structural design of your project. More importantly, the long-term maintainability of your codebase will be improved, because you’ll be dealing with less pieced code. However, there is a catch — this is only true when your class declaration is done in the right way such that the benefits of defining custom classes can outweigh the overhead of managing them.
In this article, I’d like to review nine important best practices that you should consider applying to your custom classes.
1. Good Names
When you’re defining your own class, you’re adding a new baby to your codebase. You should give the class a very good name. Although the only limit of your class name is the rules of a legal Python variable (e.g., can’t start with a number), there are preferred ways to give class names.
Use nouns that are easy to pronounce. It’s especially important if you work on a team project. During a group presentation, you probably don’t want to be the person to say, “in this case, we create an instance of the Zgnehst class.” In addition, being easy to pronounce also means the name shouldn’t be too long. I can barely think of cases when you need to use more than three words to define a class name. One word is best, two words are good, and three words are the limit.
Reflect its stored data and intended functionalities. It’s like in our real life — boys are given boy names. When we see boy names, we expect the kids are boys. It applies to class names too (or any other variables in general). The rule is simple— Don’t surprise people. If you’re dealing with the students’ information, the class should be named Student. KiddosAtCampus isn’t making the most common sense.
Follow naming conventions. We should use upper-case camel style for class names, like GoodName. The following is an incomplete list of unconventional class names: goodName, Good_Name, good_name, and GOodnAme. Following naming conventions is to make your intention clear. When people read your code, they can safely assume that an object with names like GoodName is a class.
There are also naming rules and conventions that apply to attributes and functions. In the below sections, I’ll briefly mention them where applicable, but the overall principles are the same. The only rule of thumb is simple: Don’t surprise people.
2. Explicit Instance Attributes
In most cases, we want to define our own instance initialization method (i.e., __init__). In this method, we set the initial state of our newly created instances of the class. However, Python doesn’t restrict where you can define instance attributes with custom classes. In other words, you can define additional instance attributes in later operations after the instance has been created. The following code shows you a possible scenario.
Initialization Method
As shown above, we can create an instance of the Student class by specifying a student’s first and last names. Later, when we call the instance method (i.e., verify_registration_status), the Student instance’s status attribute will be set. However, this isn’t the desired pattern, because if you spread various instance attributes throughout the entire class, you’re not making the class clear what data an instance object holds. Thus, the best practice is to place an instance’s attributes in the __init__ method, such that your code’s reader has a single place to get to know your class’s data structure, as shown below.
Better Initialization Method
For those instance attributes that you can’t set initially, you can set them with placeholder values, such as None. Although it’s of less concern, this change also helps prevent the possible error when you forget to call some instance methods to set the applicable instance attributes, causing AttributeError (‘Student’ object has no attribute ‘status_verified’).
In terms of the naming rules, the attributes should be named using lower cases and follow the snake case style, which means that if you use multiple words, connect them with underscores. Moreover, all the names should have meaningful indication regarding what data it holds (e.g., first_name is better than fn).
3. Use Properties — But Parsimoniously
Some people learn Python coding with an existing background of other OOP languages, such as Java, and they’re used to creating getters and setters for attributes of the instances. This pattern can be mimicked with the use of the property decorator in Python. The following code shows you the basic form of using the property decorator to implement getters and setters.
Property Decorator
Once this property is created, we can use it as regular attributes using the dot notation, although it’s implemented using functions under the hood.
Use Properties
As you may know, the advantages of using property implementations include verification of proper value settings (check a string is used, not an integer) and read-only access (by not implementing the setter method). However, you should use properties parsimoniously. It can be very distracting if your custom class looks like the below — there are too many properties!
Abuse of Properties
In most cases, these properties can be replaced with instance attributes, and thus we can access them and set them directly. Unless you have specific needs for the benefits of using properties as discussed (e.g., value verification), using attributes is preferred over creating properties in Python.
4. Define Meaningful String Representations
In Python, functions that have double underscores before and after the name are referred to as special or magic methods, and some people call them dunder methods. They have special usages for basic operations by the interpreter, including the __init__ method that we’ve covered previously. Two special methods, __repr__ and __str__, are essential for creating proper string representations of your custom class, which will give the code readers more intuitive information about your classes.
Between them, the major difference is that the __repr__ method defines the string, using which you can re-create the object by calling eval(repr(“the repr”)), while the __str__ method defines the string that is more descriptive and allows more customization. In other words, you can think that the string defined in the __repr__ method is to be viewed by developers while that used in the __str__ method is to be viewed by regular users. The following shows you an example.
Implementation of String Representations
Please note that in the __repr__ method’s implementation (Line 7), the f-string uses !r which will show these strings with quotation marks, because they’re necessary to construct the instance with strings properly formatted. Without the !r formatting, the string will be Student(John, Smith), which isn’t the correct way to construct a Student instance. Let’s see how these implementations show the strings for us. Specifically, the __repr__ method is called when you access the object in the interactive interpreter, while the __str__ method is called by default when you print the object.
String Representations
5. Instance, Class, and Static Methods
In a class, we can define three kinds of methods: instance, class, and static methods. You need to consider what methods you should use for the functionalities of concern. Here are some general guidelines.
If the methods are concerned with individual instance objects, for example, you need to access or update particular attributes of an instance, in which cases, you should use instance methods. These methods have a signature like this: def do_something(self):, in which the self argument refers to the instance object that calls the method. To know more about the self argument, you can refer to my previous article on this topic.
If the methods are not concerned with individual instance objects, you should consider using class or static methods. Both methods can be easily defined with applicable decorators: classmethod and staticmethod. The difference between these two is that class methods allow you to access or update attributes related to the class, while static methods are independent of any instance or the class itself. A common example of a class method is providing a convenience instantiation method, while a static method can be simply a utility function. The following code shows you some examples.
Different Kinds of Methods
In a similar fashion, you can also create class attributes. Unlike instance attributes that we discussed earlier, class attributes are shared by all instance objects, and they should reflect some characteristics independent of individual instance objects.
6. Encapsulation Using Private Attributes
When you write custom classes for your project, you need to take into account encapsulation, especially if you’re expecting that others will use your classes too. When the functionalities of the class grow, some functions or attributes are only relevant for data processing within the class. In other words, outside the class, these functions won’t be called and other users of your class won’t even care about the implementation details of these functions. In these scenarios, you should consider encapsulation.
One important way to apply encapsulation is to prefix attributes and functions with an underscore or two underscores, as a convention. The subtle difference is that those with an underscore are considered protected, while those with two underscores are considered private, which involves name-mangling after its creation. Differentiating these two categories is beyond the scope of the present article, and one of my previous articles have covered them.
In essence, by naming attributes and functions this way, you’re telling the IDEs (i.e., integrated development environment, such as PyCharm) that they’re not going to be accessed outside the class, although true private attributes don’t exist in Python. In other words, they’re still accessible if we choose so.
Encapsulation
The above code shows you a trivial example of encapsulation. For a student, we may be interested in knowing their average GPA, and we can get the point using the get_mean_gpa method. The user doesn’t need to know how the mean GPA is calculated, such that we can make related methods protected by placing an underscore prefixing the function names.
The key takeaway for this best practice is that you expose only the minimal number of public APIs that are relevant for the users to use your code. For those that are used only internally, make them protected or private methods.
7. Separate Concerns and Decoupling
With the development of your project, you find out that you’re dealing with more data, your class can become cumbersome if you’re sticking to one single class. Let’s continue with the example of the Student class. Suppose that students have lunch at school, and each of them has a dining account that they can use to pay for meals. Theoretically, we can deal with account-related data and functionalities within the Student class, as shown below.
Mixed Functionalities
The above code shows you some pseudocode on checking account balance and loading money to the account, both of which are implemented in the Student class. Imagine that there are more operations that can be related to the account, such as suspending a lost card, consolidating accounts — to implement all of them will make the Student class larger and larger, which make it gradually more difficult to maintain. Instead, you should isolate these responsibilities and make your Student class irresponsible for these account-related functionalities — a design pattern termed as decoupling.
Separated Concerns
The above code shows you how we can design the data structures with an additional Account class. As you can see, we move all account-related operations into the Account class. To retrieve the account information for the student, the Student class will handle the functionality by retrieving information from the Account class. If we want to implement more functions related to the class, we can simply update the Account class only.
The main takeaway for the design pattern is that you want your individual classes to have separate concerns. By having these responsibilities separated, your classes become smaller, which makes future changes easier, because you’ll be dealing with smaller code components.
8. Consider __slots__ For Optimization
If your class is used mostly as data containers for storing data only, you can consider using __slots__ to optimize the performance of your class. It doesn’t only increase the speed of attribute accessing but also saves memory, which can be a big benefit if you need to create thousands or many more instance objects. The reason is that for a regular class, instance attributes are stored through an internally managed dictionary. By contrast, with the use of the __slots__, instance attributes will be stored using array-related data structures implemented using C under the hood, and their performance is optimized with much higher efficiency.
Use of __slots__ in Class Definition
The above code shows you a trivial example of how we implement the __slots__ in a class. Specifically, you list all the attributes as a sequence, which will create a one-to-one match in data storage for faster access and less memory consumption. As just mentioned, regular classes use a dictionary for attribute accessing but not for those with __slots__ implemented. The following code shows you such a fact.
No __dict__ in Classes With __slots__
A detailed discussion of using __slots__ can be found in a nice answer on Stack Overflow, and you can find more information from the official documentation. Regarding the gained benefits of faster access and saved memory, a recent Medium article has a very good demonstration, and I’m not going to expand on this. However, one thing to note is that using __slots__ will have a side effect — it prevents you from dynamically creating additional attributes. Some people propose it as a mechanism for controlling what attributes your class has, but it’s not how it was designed.
9. Documentation
Last, but not least, we have to talk about documentation of your class. Most importantly, we need to understand that writing documents isn’t replacing any code. Writing tons of documents doesn’t improve your code’s performance, and it doesn’t necessarily make your code more readable. If you have to rely on docstrings to clarify your code, it’s very likely that your code has problems. I truly believe that your code should speak all by itself. The following code just shows you a mistake that some programmers can make — using unnecessary comments to compensate for bad code (i.e., meaningless variable names in this case). By contrast, some good code with good names doesn’t even need comments.
Bad Comment Examples
I’m not saying that I’m against writing comments and docstrings, but it really depends on your use cases. If your code is used by more than one person or more than one occasion (e.g., you’re the only one accessing the code but for multiple times), you should consider writing some good comments. They can help yourself or your teammates read your code, but no one should assume that your code does exactly what’s said in the comments. In other words, writing good code is always the top priority that you need to keep in mind.
If particular portions of your code are to be used by end users, you want to write docstrings, because those people aren’t familiar with the relevant codebase. All they want to know is how to use the pertinent APIs, and the docstrings will form the basis for the help menu. Thus, it’s your responsibility as the programmer to make sure that you provide clear instructions on how to use your programs.
Conclusions
In this article, we reviewed important factors that you need to consider when you define your own classes. If you’re new to Python or programming in general, you may not fully understand every aspect that we’ve discussed, which is OK. The more you code, the more you’ll find the importance of having these principles in mind before you define your classes. Practice these guidelines continuously when you work with classes because a good design will save much of your development time later.