2013-08-06 5 views
0

내가 파이썬에서 발전기 기능을 사용하여 연습, 그래서 다음과 같이 나는 기능을 정의 :사용 발전기 기능 파이썬

def MySQL_product(): 
    #Establish connection to database 
    try: 
     connection = msql.connect(host = 'localhost', user = 'max', passwd = 'password', db = 'schools') 
    except: 
     pass 

    #Iterate through each product and insert them in database 
    with connection: 
     cursor = connection.cursor() 
     cursor.execute("SELECT name, age, gender, school 
        WHERE GroupId = 'student' AND Exchange = 'foreign'") 
     for product in cursor.fetchall(): 
      yield product 

def main(): 
    for column in range (0, number_of_schools): 
     for product in MySQL_product(): 
      print product 

을하지만, 나는이 코드를 실행하면, 내가 출력으로 표시되는 모든 내가 노력하고 generator object at ...한다 데이터베이스에있는 내용을 인쇄합니다. 또한 MySQL_product()에있는 print 문 중 하나도 실행되지 않습니다. 생성자의 요점은 데이터베이스의 모든 행 목록을 반환하는 대신 하나씩 반환해야한다는 것입니다. 그런 다음 해당 항목에 액세스하거나 인쇄하려고했습니다. 이 코드를 수정하려면 어떻게해야합니까?

답변

3

cursor.fetchall()을 수행 중이라면 SQL Server에서 사용 가능한 모든 결과를 파이썬의 메모리에 복사한다는 의미입니다. 그래서이 상황에서 발전기는 당신에게 아무것도주지 않습니다.

cursor.fetchmany() 또는 cursor.fetchone() 대신에 'some'또는 'one'결과를 한 번에 처리하기 때문에 Python 측에서 메모리 사용량 만 볼 수 있습니다. SQL 측에서는 서버가 여전히 결과 세트를 캐쉬 (SQL 서버에 귀중한 자원을 낭비)시킨다.

궁극적으로 - 결과를 청크로 처리했다면 -

while there_are_more_results: 
    results = cursor.fetchmany(10) 
    for result in results: 
     do_something(result) 

생성기가 있으면 MySQL에서 더 많은 결과를 얻는 동안 차단해야하므로 실질적인 이점이 없습니다.

그러나, 당신은 당신이 일이 코드를 만들기 위해 무엇을 원하는 질문

에 대답하는 것입니다 : 당신이 비동기 적으로 일을 할 때

def main(): 
    for column in range (0, number_of_schools): 
     for student in MySQL_product(): 
      print student 

발전기는 정말 유용합니다 - 기본적으로 만약 발전기가 아직 준비되지 않았습니다 - 그냥 건너 뛰고 다른 것들도 작동하게하십시오.

+0

그래서'main'을 실행할 때 MySQL_product()에서'fetchall()'을'fetchone()'으로 변경합니까? –

+0

한 번에 하나의 결과를 가져 오는 것은 꽤 느릴 수 있습니다. 최적의 크기는 mysql 서버가 조정되는 방법에 따라 다릅니다. 출발점으로 256을 시도하십시오. – synthesizerpatel

+0

내가 무슨 말을하는지 잘 모르겠다면 편집 된 질문을 볼 수 있을까요? 네가하는 말을 이해한다면이 문제에서 발전기를 효율적으로 사용할 수 없습니까? –

0

제 첫 대답이 잘못되었고 다른 사람들이 이미 최상의 해결책을 제시해 주었기 때문에 대안과 잠재적 유스 케이스를 말씀 드리겠습니다. 한 번에 2 개 항목을 반복하거나 다른 사용자 지정 방식으로 반복해야하는 경우 next 메서드가 유용 할 수 있습니다.

def gen(): 
    for i in range(20): 
     yield i 

for i in gen(): 
    print "Center", str(i).center(10) 

a = gen()  
for i in range(10): 
    left = str(a.next()).ljust(10) 
    right = str(a.next()).rjust(10) 
+1

인쇄 students.next()는 하나의 결과 만 인쇄합니다. 발전기를 반복해야합니다. – synthesizerpatel

+0

예, 그 사실을 깨닫기 시작했습니다. –

2

예, 생성기 동작 방식입니다. 항상 반복기를 반환합니다. for 성명 당신은 아마 이런 일에 main() 기능을 변경하려면 :

def main(): 
    for column in range (0, number_of_schools): 
     for student in MySQL_product(): 
      print student 

그것은 next() 기능 반복자에 의해 산출 다음 결과를 얻을 수도 있지만, 일반적으로 당신은 (때문에 for item in iterator: # ...와 직접 반복하는 것을 선호한다 코드는 읽기 쉽고, 생성기 기능에서 목록을 반환하는 일반 기능으로 전환하는 것과 같은 일을하는 경우 취약하지 않습니다.

+0

내'MySQL_product()'함수는'fetchall()'을 어떻게 변경합니까? –

+0

@MaxKim 잘 몰라요. 나는 당신의'MySQL_product()'함수를 들여다 보지 않았다. 그러나 @synthesizerpatel이 당신을 덮어 준 것처럼 보인다. –