수업 방법의 목적은 무엇입니까?
나는 나 자신에게 파이썬을 가르치고 있으며 가장 최근의 교훈은 파이썬이 Java가 아니라는 것이므로 모든 클래스 메소드를 함수로 바꾸는 데 시간을 보냈습니다.
이제 static
Java에서 메소드로 수행 할 작업에 클래스 메소드를 사용할 필요가 없다는 것을 알고 있지만 언제 사용할지 확실하지 않습니다. 파이썬 클래스 메소드에 대해 찾을 수있는 모든 조언은 나와 같은 초보자 라인을 따르고 있으며 표준 문서는 논의 할 때 가장 불투명합니다.
누구나 파이썬에서 클래스 메소드를 사용하는 좋은 예가 있습니까? 아니면 클래스 메소드를 현명하게 사용할 수있는 시점을 누군가가 말해 줄 수 있습니까?
클래스 메소드는 특정 인스턴스에 국한되지 않지만 여전히 어떤 방식으로 클래스를 포함하는 메소드가 필요한 경우를위한 것입니다. 그들에 대한 가장 흥미로운 점은 서브 클래스에 의해 재정의 될 수 있다는 것입니다. 하위 클래스는 Java의 정적 메소드 또는 Python의 모듈 레벨 함수에서는 불가능합니다.
class MyClass
와 MyClass (공장, 의존성 주입 스터브 등)에서 작동하는 모듈 수준 함수가 있다면 그것을 a로 만드십시오 classmethod
. 그러면 서브 클래스에서 사용할 수 있습니다.
팩토리 메소드 (대체 생성자)는 실제로 클래스 메소드의 전형적인 예입니다.
기본적으로 클래스 메소드는 클래스의 네임 스페이스에 자연스럽게 맞는 메소드를 원할 때마다 적합하지만 클래스의 특정 인스턴스와 연관되지 않습니다.
예를 들어, 우수한 유니 패스 모듈에서 :
현재 디렉토리
Path.cwd()
- 실제 현재 디렉토리를 리턴하십시오. 예를 들어,
Path("/tmp/my_temp_dir")
. 이것은 클래스 방법입니다.
- 실제 현재 디렉토리를 리턴하십시오. 예를 들어,
.chdir()
- self를 현재 디렉토리로 만드십시오.
현재 디렉토리는 전체 프로세스이므로 cwd
메소드에는 연관시킬 특정 인스턴스가 없습니다. 그러나 cwd
주어진 Path
인스턴스 의 디렉토리로 변경하는 것은 실제로 인스턴스 방법이어야합니다.
흠 ... Path.cwd()
실제로 Path
인스턴스를 반환하는 것처럼 팩토리 메서드로 간주 될 수 있다고 생각합니다 ...
일반적인 방법은 디스패치의 세부 사항을 숨기는 데 유용 myobj.foo()
합니다. foo()
메소드가 myobj
객체의 클래스 또는 부모 클래스 중 하나에 의해 구현 되는지 걱정할 필요없이 입력 할 수 있습니다. 클래스 메소드는 이것과 정확히 유사하지만 클래스 객체를 대신 사용합니다. 고유 한 특수 버전이 필요하기 때문에 특별히 구현 되었는지 또는 부모 클래스가 호출을 처리 할 수 있는지 MyClass.foo()
에 대해 걱정할 필요없이 호출 할 수 있습니다 .foo()
MyClass
인스턴스가 존재할 때까지 인스턴스를 메소드 호출의 디스패치 지점으로 사용할 수 없기 때문에 실제 인스턴스를 작성하기 전에 설정 또는 계산을 수행 할 때 클래스 메소드가 필수적 입니다. SQLAlchemy 소스 코드에서 좋은 예를 볼 수 있습니다. dbapi()
다음 링크에서 클래스 메소드를 살펴보십시오 .
당신은 것을 볼 수 있습니다 dbapi()
그것을 실행해야하기 때문에 데이터베이스 백엔드 사용이 주문형 필요로하는 공급 업체 특정 데이터베이스 라이브러리를 가져올 수있는 방법, 수업 방법입니다 전에 생성 받기 시작 특정 데이터베이스 연결의 경우 - 그러나 그것이 수 없어 간단한 함수 또는 정적 함수입니다. 부모 클래스보다 서브 클래스에서 더 구체적으로 작성 해야하는 다른 지원 메소드를 호출 할 수 있기를 원하기 때문입니다. 그리고 함수 나 정적 클래스로 디스패치하면 초기화를 수행하는 클래스에 대한 지식을 "잊어"버립니다.
최근에는 프로그래밍 방식으로 설정할 수있는 로깅 수준에 따라 다양한 양의 출력을 출력하는 매우 가벼운 로깅 클래스가 필요했습니다. 그러나 디버깅 메시지 또는 오류 또는 경고를 출력하려고 할 때마다 클래스를 인스턴스화하고 싶지 않았습니다. 그러나 나는 또한이 로깅 기능을 캡슐화하고 전역 선언없이 재사용 할 수있게하고 싶었습니다.
그래서 클래스 변수와 @classmethod
데코레이터를 사용하여 이것을 달성했습니다.
간단한 로깅 클래스를 사용하여 다음을 수행 할 수 있습니다.
Logger._level = Logger.DEBUG
그런 다음 내 코드에서 많은 디버깅 정보를 뱉어 내려면 간단히 코딩해야했습니다.
Logger.debug( "this is some annoying message I only want to see while debugging" )
오류가 발생할 수 있습니다
Logger.error( "Wow, something really awful happened." )
"제작"환경에서 지정할 수 있습니다
Logger._level = Logger.ERROR
이제 오류 메시지 만 출력됩니다. 디버그 메시지가 인쇄되지 않습니다.
여기 내 수업이 있습니다.
class Logger :
''' Handles logging of debugging and error messages. '''
DEBUG = 5
INFO = 4
WARN = 3
ERROR = 2
FATAL = 1
_level = DEBUG
def __init__( self ) :
Logger._level = Logger.DEBUG
@classmethod
def isLevel( cls, level ) :
return cls._level >= level
@classmethod
def debug( cls, message ) :
if cls.isLevel( Logger.DEBUG ) :
print "DEBUG: " + message
@classmethod
def info( cls, message ) :
if cls.isLevel( Logger.INFO ) :
print "INFO : " + message
@classmethod
def warn( cls, message ) :
if cls.isLevel( Logger.WARN ) :
print "WARN : " + message
@classmethod
def error( cls, message ) :
if cls.isLevel( Logger.ERROR ) :
print "ERROR: " + message
@classmethod
def fatal( cls, message ) :
if cls.isLevel( Logger.FATAL ) :
print "FATAL: " + message
그리고 약간 테스트하는 코드 :
def logAll() :
Logger.debug( "This is a Debug message." )
Logger.info ( "This is a Info message." )
Logger.warn ( "This is a Warn message." )
Logger.error( "This is a Error message." )
Logger.fatal( "This is a Fatal message." )
if __name__ == '__main__' :
print "Should see all DEBUG and higher"
Logger._level = Logger.DEBUG
logAll()
print "Should see all ERROR and higher"
Logger._level = Logger.ERROR
logAll()
대체 생성자가 전형적인 예입니다.
사용자가 내 웹 사이트에 로그인하면 사용자 이름과 비밀번호로 User () 객체가 인스턴스화됩니다.
로그인 할 사용자가없는 사용자 객체가 필요한 경우 (예 : 관리자 사용자가 다른 사용자 계정을 삭제하고 싶을 수 있으므로 해당 사용자를 인스턴스화하고 delete 메소드를 호출해야합니다) :
사용자 객체를 가져 오는 클래스 메소드가 있습니다.
class User():
#lots of code
#...
# more code
@classmethod
def get_by_username(cls, username):
return cls.query(cls.username == username).get()
@classmethod
def get_by_auth_id(cls, auth_id):
return cls.query(cls.auth_id == auth_id).get()
가장 명확한 대답은 AmanKow의 것입니다. 코드 구성 방법으로 요약됩니다. 모듈의 네임 스페이스에 싸여있는 모듈 레벨 함수로 모든 것을 작성할 수 있습니다.
module.py (file 1)
---------
def f1() : pass
def f2() : pass
def f3() : pass
usage.py (file 2)
--------
from module import *
f1()
f2()
f3()
def f4():pass
def f5():pass
usage1.py (file 3)
-------------------
from usage import f4,f5
f4()
f5()
위의 절차 적 코드는 잘 구성되어 있지 않습니다. 혼란스러워하는 3 개의 모듈 만 후에 볼 수 있듯이 각 방법은 무엇입니까? 자바와 같이 함수에 긴 설명 이름을 사용할 수 있지만 여전히 코드를 관리하기가 매우 빠릅니다.
객체 지향 방식은 코드를 관리 가능한 블록으로 분류하는 것입니다. 즉, 클래스 및 객체 및 함수는 객체 인스턴스 또는 클래스와 연관 될 수 있습니다.
클래스 함수를 사용하면 모듈 수준 함수와 비교하여 코드에서 다른 수준의 나누기를 얻을 수 있습니다. 따라서 클래스 내에서 관련 기능을 그룹화하여 해당 클래스에 할당 된 작업에보다 구체적으로 지정할 수 있습니다. 예를 들어 파일 유틸리티 클래스를 만들 수 있습니다.
class FileUtil ():
def copy(source,dest):pass
def move(source,dest):pass
def copyDir(source,dest):pass
def moveDir(source,dest):pass
//usage
FileUtil.copy("1.txt","2.txt")
FileUtil.moveDir("dir1","dir2")
이 방법은보다 유연하고 유지 관리가 가능하며 기능을 그룹화하고 각 기능이하는 일에 대해보다 명확합니다. 또한 이름 충돌을 방지합니다. 예를 들어 코드에서 사용하는 다른 가져온 모듈 (예 : 네트워크 복사)에 함수 복사본이있을 수 있으므로 전체 이름 FileUtil.copy ()를 사용하면 문제가 해결되고 복사 기능이 모두 나란히 사용할 수 있습니다.
솔직히? staticmethod 또는 classmethod를 사용한 적이 없습니다. 전역 함수 또는 인스턴스 메소드를 사용하여 수행 할 수없는 작업을 아직 보지 못했습니다.
파이썬이 Java처럼 개인 및 보호 멤버를 더 많이 사용하면 달라집니다. Java에서는 인스턴스의 개인 멤버에 액세스하여 작업을 수행 할 수있는 정적 메소드가 필요합니다. 파이썬에서는 거의 필요하지 않습니다.
일반적으로 정적 메소드와 클래스 메소드를 사용하는 사람들은 파이썬의 모듈 레벨 네임 스페이스를 더 잘 사용하는 것만 봅니다.
호환 가능한 클래스와 함께 사용할 수있는 일반 클래스 메소드를 작성할 수 있습니다.
예를 들면 다음과 같습니다.
@classmethod
def get_name(cls):
print cls.name
class C:
name = "tester"
C.get_name = get_name
#call it:
C.get_name()
사용하지 않으면 @classmethod
self 키워드로 수행 할 수 있지만 Class 인스턴스가 필요합니다.
def get_name(self):
print self.name
class C:
name = "tester"
C.get_name = get_name
#call it:
C().get_name() #<-note the its an instance of class C
나는 PHP로 일 했었고 최근에 나 자신에게 물었다.이 클래스 메소드는 어떻게 진행되고 있습니까? 파이썬 매뉴얼은 매우 기술적이고 단어가 짧기 때문에 그 기능을 이해하는 데 도움이되지 않습니다. 인터넷 검색 및 인터넷 검색을 통해 answer-> http://code.anjanesh.net/2007/12/python-classmethods.html을 찾았습니다 .
당신이 그것을 클릭 게으른 경우. 내 설명은 더 짧고 아래입니다. :)
PHP에서 (모두 PHP를 아는 것은 아니지만이 언어는 너무 간단하여 누구나 내가 말하는 것을 이해해야합니다) 우리는 다음과 같은 정적 변수를 가지고 있습니다 :
class A
{
static protected $inner_var = null;
static public function echoInnerVar()
{
echo self::$inner_var."\n";
}
static public function setInnerVar($v)
{
self::$inner_var = $v;
}
}
class B extends A
{
}
A::setInnerVar(10);
B::setInnerVar(20);
A::echoInnerVar();
B::echoInnerVar();
결과는 두 경우 모두 20입니다.
그러나 파이썬에서는 @classmethod 데코레이터를 추가 할 수 있으므로 각각 10과 20을 출력 할 수 있습니다. 예:
class A(object):
inner_var = 0
@classmethod
def setInnerVar(cls, value):
cls.inner_var = value
@classmethod
def echoInnerVar(cls):
print cls.inner_var
class B(A):
pass
A.setInnerVar(10)
B.setInnerVar(20)
A.echoInnerVar()
B.echoInnerVar()
똑똑하지 않습니까?
클래스 방법은 "의미 적 설탕"(이 용어가 널리 사용되는지 알지 못함) 또는 "의미 적 편의성"을 제공합니다.
예 : 객체를 나타내는 클래스 세트가 있습니다. 당신은 클래스 메소드가 할 수 있습니다 all()
또는 find()
쓰기 User.all()
또는 User.find(firstname='Guido')
. 물론 모듈 수준의 기능을 사용하여 수행 할 수 있습니다 ...
루비에서 나왔던 것은 소위 클래스 메소드와 소위 인스턴스 메소드는 첫 번째 매개 변수에 시맨틱 의미가 적용된 함수 일 뿐이며 함수 가 메소드로 호출 될 때 자동으로 전달됩니다. 의 객체 (예 obj.meth()
).
일반적으로 해당 객체 는 인스턴스 여야하지만 @classmethod
메소드 데코레이터 는 클래스를 전달하도록 규칙을 변경합니다. 인스턴스에서 클래스 메소드를 호출 할 수 있습니다 (단지 함수 일뿐입니다). 첫 번째 인수는 클래스입니다.
함수일 뿐이므로 주어진 범위 (즉, class
정의) 에서 한 번만 선언 할 수 있습니다 . 따라서 Rubyist에게 놀랍게도 같은 이름의 클래스 메소드와 인스턴스 메소드를 가질 수 없습니다 .
이걸 고려하세요:
class Foo():
def foo(x):
print(x)
foo
인스턴스를 호출 할 수 있습니다
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
그러나 수업이 아닙니다.
Foo.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
이제 추가하십시오 @classmethod
:
class Foo():
@classmethod
def foo(x):
print(x)
인스턴스를 호출하면 이제 해당 클래스를 전달합니다.
Foo().foo()
__main__.Foo
클래스를 호출하는 것처럼 :
Foo.foo()
__main__.Foo
self
인스턴스 메소드와 cls
클래스 메소드에서 첫 번째 인수에 사용하도록 지시하는 것은 컨벤션뿐입니다 . 나는 그것이 단지 논쟁이라는 것을 설명하기 위해 여기에서 사용하지 않았다. 루비에서, self
A는 키워드.
루비와 대조 :
class Foo
def foo()
puts "instance method #{self}"
end
def self.foo()
puts "class method #{self}"
end
end
Foo.foo()
class method Foo
Foo.new.foo()
instance method #<Foo:0x000000020fe018>
파이썬 클래스 메소드는 단지 꾸며진 함수 이며, 같은 기법을 사용하여 자신 만의 데코레이터 를 만들 수 있습니다 . 데코 레이팅 된 메소드는 실제 메소드를 랩핑합니다 ( @classmethod
추가 클래스 인수를 전달하는 경우 ). 기본 방법은 아직 숨겨져 있지만 여전히 액세스 할 수 있습니다 .
각주 : 클래스와 인스턴스 메소드 사이의 이름 충돌로 호기심이 생겼습니다. 나는 파이썬 전문가와 거리가 멀며, 이것 중 하나라도 잘못되면 의견을 원합니다.
이것은 흥미로운 주제입니다. 파이썬 클래스 메소드는 팩토리가 아닌 싱글 톤처럼 작동한다는 것입니다 (생산 된 클래스의 인스턴스를 반환합니다). 싱글 톤의 이유는 클래스에 대해 한 번만 생성되지만 모든 인스턴스가 공유하는 공통 오브젝트 (사전)가 있기 때문입니다.
여기에 이것을 설명하는 예가 있습니다. 모든 인스턴스에는 단일 사전에 대한 참조가 있습니다. 내가 이해할 때 이것은 공장 패턴이 아닙니다. 이것은 아마도 파이썬에게 매우 독창적입니다.
class M():
@classmethod
def m(cls, arg):
print "arg was", getattr(cls, "arg" , None),
cls.arg = arg
print "arg is" , cls.arg
M.m(1) # prints arg was None arg is 1
M.m(2) # prints arg was 1 arg is 2
m1 = M()
m2 = M()
m1.m(3) # prints arg was 2 arg is 3
m2.m(4) # prints arg was 3 arg is 4 << this breaks the factory pattern theory.
M.m(5) # prints arg was 4 arg is 5
나는 몇 번이나 같은 질문을했다. 그리고 여기에있는 사람들이 그것을 설명하려고 열심히 노력했지만 IMHO가 찾은 가장 좋은 대답 (그리고 가장 간단한 대답) 은 Python Documentation의 Class 메소드에 대한 설명 입니다.
정적 메소드에 대한 참조도 있습니다. 누군가 누군가 이미 인스턴스 메소드를 알고있는 경우 (이 가정),이 답변은 모두 함께하는 마지막 조각 일 수 있습니다 ...
이 주제에 대한보다 자세한 설명은 다음 문서에서도 찾을 수 있습니다 . 표준 유형 계층 구조 ( 인스턴스 메소드 섹션으로 스크롤 )
물론 클래스는 인스턴스 집합을 정의합니다. 그리고 클래스의 메소드는 개별 인스턴스에서 작동합니다. 클래스 메소드 (및 변수)는 인스턴스 세트와 관련된 다른 정보를 걸 수있는 장소입니다.
예를 들어, 수업에서 학생 세트를 정의하는 경우 학생이 소속 될 수있는 학년 세트와 같은 것을 정의하는 클래스 변수 또는 방법을 원할 수 있습니다.
클래스 메소드를 사용하여 전체 세트 작업을위한 도구를 정의 할 수도 있습니다. 예를 들어 Student.all_of_em ()은 알려진 모든 학생을 반환 할 수 있습니다. 분명히 인스턴스 집합이 집합보다 많은 구조를 가지고 있다면 해당 구조에 대해 알 수있는 클래스 메서드를 제공 할 수 있습니다. Students.all_of_em (grade = 'juniors')
이와 같은 기술은 인스턴스 집합의 멤버를 클래스 변수에 기반한 데이터 구조에 저장하는 경향이 있습니다. 가비지 수집을 방해하지 않도록주의해야합니다.
참고 URL : https://stackoverflow.com/questions/38238/what-is-the-purpose-of-class-methods
'Programing' 카테고리의 다른 글
내 git 저장소에 virtualenv 디렉토리를 두는 것이 좋지 않습니까? (0) | 2020.04.09 |
---|---|
EC2에서 '중지 된'인스턴스에 대한 요금이 부과됩니까? (0) | 2020.04.09 |
Vim에서 설정의 현재 값 가져 오기 (0) | 2020.04.09 |
-XX : MaxPermSize의 기능은 무엇입니까? (0) | 2020.04.09 |
Get. 대신 POST로 리디렉션? (0) | 2020.04.09 |