Source Project: MPContribs   Author: materialsproject   File: views.py    License: MIT License 18 votes  
def get_browser():
    if "browser" not in g:
        options = webdriver.ChromeOptions()
        options.add_argument("no-sandbox")
        options.add_argument("--disable-gpu")
        options.add_argument("--window-size=800,600")
        options.add_argument("--disable-dev-shm-usage")
        options.set_headless()
        host = "chrome" if current_app.config["DEBUG"] else "127.0.0.1"
        g.browser = webdriver.Remote(
            command_executor=f"http://{host}:4444/wd/hub",
            desired_capabilities=DesiredCapabilities.CHROME,
            options=options,
        )
    return g.browser 
Example #2
Source Project: NoXss   Author: lwzSoviet   File: util.py    License: MIT License 12 votes  
def chrome(headless=False):
    # support to get response status and headers
    d = DesiredCapabilities.CHROME
    d['loggingPrefs'] = {'performance': 'ALL'}
    opt = webdriver.ChromeOptions()
    if headless:
        opt.add_argument("--headless")
    opt.add_argument("--disable-xss-auditor")
    opt.add_argument("--disable-web-security")
    opt.add_argument("--allow-running-insecure-content")
    opt.add_argument("--no-sandbox")
    opt.add_argument("--disable-setuid-sandbox")
    opt.add_argument("--disable-webgl")
    opt.add_argument("--disable-popup-blocking")
    # prefs = {"profile.managed_default_content_settings.images": 2,
    #          'notifications': 2,
    #          }
    # opt.add_experimental_option("prefs", prefs)
    browser = webdriver.Chrome(options=opt,desired_capabilities=d)
    browser.implicitly_wait(10)
    browser.set_page_load_timeout(20)
    return browser 
Example #3
Source Project: realbrowserlocusts   Author: nickboucart   File: locusts.py    License: MIT License 10 votes  
def __init__(self):
        super(HeadlessChromeLocust, self).__init__()
        options = webdriver.ChromeOptions()
        options.add_argument('headless')
        options.add_argument('window-size={}x{}'.format(
            self.screen_width, self.screen_height
        ))
        options.add_argument('disable-gpu')
        if self.proxy_server:
            _LOGGER.info('Using proxy: ' + self.proxy_server)
            options.add_argument('proxy-server={}'.format(self.proxy_server))
        driver = webdriver.Chrome(chrome_options=options)
        _LOGGER.info('Actually trying to run headless Chrome')
        self.client = RealBrowserClient(
            driver,
            self.timeout,
            self.screen_width,
            self.screen_height,
            set_window=False
        ) 
Example #4
Source Project: scripts   Author: KiriKira   File: ipip.py    License: MIT License 10 votes  
def create_driver():
    option = webdriver.ChromeOptions()
    option.add_argument("--headless")
    option.add_argument("--host-resolver-rules=MAP www.google-analytics.com 127.0.0.1")
    option.add_argument('user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36')
    return webdriver.Chrome(options=option) 
Example #5
Source Project: king-bot   Author: breuerfelix   File: custom_driver.py    License: MIT License 9 votes  
def headless(self, path: str, proxy: str = "") -> None:
        ua = UserAgent()
        userAgent = ua.random
        options = webdriver.ChromeOptions()
        options.add_argument("headless")
        options.add_argument("window-size=1500,1200")
        options.add_argument("no-sandbox")
        options.add_argument("disable-dev-shm-usage")
        options.add_argument("disable-gpu")
        options.add_argument("log-level=3")
        options.add_argument(f"user-agent={userAgent}")

        if proxy != "":
            self.proxy = True
            options.add_argument("proxy-server={}".format(proxy))

        self.driver = webdriver.Chrome(path, chrome_options=options)
        self.set_config()
        self._headless = True 
Example #6
Source Project: ankigenbot   Author: damaru2   File: send_card.py    License: GNU General Public License v3.0 9 votes  
def __init__(self, username, password):
        self.driver = None

        self.last_access = time.time()

        options = webdriver.ChromeOptions()
        options.add_argument("--window-size=1920x1080")
        options.add_argument('--ignore-certificate-errors')
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')

        options.binary_location = "/usr/lib/chromium-browser/chromium-browser"
        self.driver = webdriver.Chrome(chrome_options=options)

        self.driver.set_window_size(1920, 1080)
        self.driver.get(CardSender.url)
        usr_box = self.driver.find_element_by_id('email')
        usr_box.send_keys(username)
        pass_box = self.driver.find_element_by_id('password')
        pass_box.send_keys('{}\n'.format(password)) 
Example #7
Source Project: wagtail-tag-manager   Author: jberghoef   File: fixtures.py    License: BSD 3-Clause "New" or "Revised" License 8 votes  
def driver():
    options = webdriver.ChromeOptions()
    options.add_argument("disable-gpu")
    options.add_argument("headless")
    options.add_argument("no-default-browser-check")
    options.add_argument("no-first-run")
    options.add_argument("no-sandbox")

    d = DesiredCapabilities.CHROME
    d["loggingPrefs"] = {"browser": "ALL"}

    driver = webdriver.Chrome(options=options, desired_capabilities=d)
    driver.implicitly_wait(30)

    yield driver
    driver.quit() 
Example #8
Source Project: python-sdk   Author: kuaidaili   File: selenium_chrome_http_auth.py    License: BSD 2-Clause "Simplified" License 8 votes  
def get_chromedriver(use_proxy=False, user_agent=None):
    # path = os.path.dirname(os.path.abspath(__file__)) # 如果没有把chromedriver放到python\script\下,则需要指定路径
    chrome_options = webdriver.ChromeOptions()
    if use_proxy:
        pluginfile = 'proxy_auth_plugin.zip'

        with zipfile.ZipFile(pluginfile, 'w') as zp:
            zp.writestr("manifest.json", manifest_json)
            zp.writestr("background.js", background_js)
        chrome_options.add_extension(pluginfile)
    if user_agent:
        chrome_options.add_argument('--user-agent=%s' % user_agent)
    driver = webdriver.Chrome(
        # os.path.join(path, 'chromedriver'),
        chrome_options=chrome_options)
    return driver 
Example #9
Source Project: content   Author: demisto   File: rasterize.py    License: MIT License 8 votes  
def init_driver(offline_mode=False):
    """
    Creates headless Google Chrome Web Driver
    """
    demisto.debug(f'Creating chrome driver. Mode: {"OFFLINE" if offline_mode else "ONLINE"}')
    try:
        chrome_options = webdriver.ChromeOptions()
        for opt in merge_options(DEFAULT_CHROME_OPTIONS, USER_CHROME_OPTIONS):
            chrome_options.add_argument(opt)
        driver = webdriver.Chrome(options=chrome_options, service_args=[
            f'--log-path={DRIVER_LOG}',
        ])
        if offline_mode:
            driver.set_network_conditions(offline=True, latency=5, throughput=500 * 1024)
    except Exception as ex:
        return_error(f'Unexpected exception: {ex}\nTrace:{traceback.format_exc()}')

    demisto.debug('Creating chrome driver - COMPLETED')
    return driver 
Example #10
Source Project: online-judge   Author: DMOJ   File: pdf_problems.py    License: GNU Affero General Public License v3.0 7 votes  
def _make(self, debug):
        options = webdriver.ChromeOptions()
        options.add_argument("--headless")
        options.binary_location = settings.SELENIUM_CUSTOM_CHROME_PATH

        browser = webdriver.Chrome(settings.SELENIUM_CHROMEDRIVER_PATH, options=options)
        browser.get('file://' + os.path.abspath(os.path.join(self.dir, 'input.html')))
        self.log = self.get_log(browser)

        try:
            WebDriverWait(browser, 15).until(EC.presence_of_element_located((By.CLASS_NAME, 'math-loaded')))
        except TimeoutException:
            logger.error('PDF math rendering timed out')
            self.log = self.get_log(browser) + '\nPDF math rendering timed out'
            return

        response = browser.execute_cdp_cmd('Page.printToPDF', self.template)
        self.log = self.get_log(browser)
        if not response:
            return

        with open(os.path.abspath(os.path.join(self.dir, 'output.pdf')), 'wb') as f:
            f.write(base64.b64decode(response['data']))

        self.success = True 
Example #11
Source Project: Python-tools   Author: wolverinn   File: power_views.py    License: MIT License 7 votes  
def get_page(url):
    chrome_options = webdriver.ChromeOptions()
    ua_argument = 'User-Agent="'+GetUserAgent()+'"'
    chrome_options.add_argument(ua_argument)
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    chrome_options.add_argument('--incognito')
    chrome_options.add_argument('log-level=3')
    try:
        driver = webdriver.Chrome(chrome_options=chrome_options)
        #driver.set_page_load_timeout(6)
        # driver.set_script_timeout(6)
        driver.get(url)
        # time.sleep(0.5)
        driver.quit()
    except:
        driver.quit()
        print("timeout") 
Example #12
Source Project: toolium   Author: Telefonica   File: config_driver.py    License: Apache License 2.0 6 votes  
def _create_chrome_options(self):
        """Create and configure a chrome options object

        :returns: chrome options object
        """
        # Get Chrome binary
        chrome_binary = self.config.get_optional('Chrome', 'binary')

        # Create Chrome options
        options = webdriver.ChromeOptions()

        if self.config.getboolean_optional('Driver', 'headless'):
            self.logger.debug("Running Chrome in headless mode")
            options.add_argument('--headless')
            if os.name == 'nt':  # Temporarily needed if running on Windows.
                options.add_argument('--disable-gpu')

        if chrome_binary is not None:
            options.binary_location = chrome_binary

        # Add Chrome preferences, mobile emulation options and chrome arguments
        self._add_chrome_options(options, 'prefs')
        self._add_chrome_options(options, 'mobileEmulation')
        self._add_chrome_arguments(options)

        return options 
Example #13
Source Project: Disney-Fastpass-Bot   Author: ethanbrimhall   File: fastpassfinder.py    License: MIT License 6 votes  
def createChromeDriver():
    print("\nOpening Chrome WebDriver...")
    options = webdriver.ChromeOptions()
    options.add_argument("--start-maximized")
    chrome_path = credentials.path

    return webdriver.Chrome(chrome_path, options=options)

#Clicks the first button on the website, the 'get started' button 
Example #14
Source Project: ESPN-Fantasy-Basketball   Author: wcrasta   File: app.py    License: MIT License 6 votes  
def run_selenium(url, is_season_data, league_id):
    options = webdriver.ChromeOptions()
    options.add_argument('headless')
    options.add_argument('no-sandbox')
    options.add_argument('disable-dev-shm-usage')
    capa = DesiredCapabilities.CHROME
    capa["pageLoadStrategy"] = "none"
    driver = webdriver.Chrome(chrome_options=options, desired_capabilities=capa)
    try:
        app.logger.info('%s - Starting selenium', league_id)
        driver.get(url)
        app.logger.info('%s - Waiting for element to load', league_id)
        # Season standings have a different URL than weekly scoreboard

        if is_season_data:
            WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CLASS_NAME, 'Table2__sub-header')))
        else:
            WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.CLASS_NAME, 'Table2__header-row')))
        app.logger.info('%s - Element loaded. Sleeping started to get latest data.', league_id)
        time.sleep(5)
        plain_text = driver.page_source
        soup = BeautifulSoup(plain_text, 'html.parser')
        app.logger.info('%s - Got BeautifulSoup object', league_id)
    except Exception as ex:
        app.logger.error('%s - Could not get page source.', league_id, ex)
        soup = None
    finally:
        driver.quit()
    return soup 

VSCode 환경에서 OpenCV 를 설치할 때 꼭 문제되는 사항이 있다.

 왠지 심리적인 느낌으로 반드시 에러가 날 거라고 생각하긴 했지만 진짜 날 줄은 몰랏다.

 

다음과 같은 문제가 발생할 수 있다.

python -m pip install --upgrade pip
python -m pip install opencv-python

 

위에서 python -m 이 없는 경우에, 즉 pip 만을 이용해서 Library Module 을 import 때리려고 하는데

인식을 못하는 것이다.

 

더 큰 문제는 위와같이 때려도 문제가 나는 경우가 있는데, 그 경우에는 머리털이 곤두서게 된다.

 

(venv) $ pip2 install opencv-python
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support
Collecting opencv-python
  Using cached opencv-python-4.3.0.38.tar.gz (88.0 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... error
  ERROR: Command errored out with exit status 1:
   command: /home/pc_user/.venvs/venv/bin/python /home/pc_user/.venvs/venv/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /tmp/tmp7q7z4L
       cwd: /tmp/pip-install-C21PKF/opencv-python
  Complete output (22 lines):
  Traceback (most recent call last):
    File "/home/pc_user/.venvs/venv/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 280, in <module>
      main()
    File "/home/pc_user/.venvs/venv/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 263, in main
      json_out['return_val'] = hook(**hook_input['kwargs'])
    File "/home/pc_user/.venvs/venv/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py", line 114, in get_requires_for_build_wheel
      return hook(config_settings)
    File "/tmp/pip-build-env-2FzygL/overlay/lib/python2.7/site-packages/setuptools/build_meta.py", line 146, in get_requires_for_build_wheel
      return self._get_build_requires(config_settings, requirements=['wheel'])
    File "/tmp/pip-build-env-2FzygL/overlay/lib/python2.7/site-packages/setuptools/build_meta.py", line 127, in _get_build_requires
      self.run_setup()
    File "/tmp/pip-build-env-2FzygL/overlay/lib/python2.7/site-packages/setuptools/build_meta.py", line 243, in run_setup
      self).run_setup(setup_script=setup_script)
    File "/tmp/pip-build-env-2FzygL/overlay/lib/python2.7/site-packages/setuptools/build_meta.py", line 142, in run_setup
      exec(compile(code, __file__, 'exec'), locals())
    File "setup.py", line 448, in <module>
      main()
    File "setup.py", line 99, in main
      % {"ext": re.escape(sysconfig.get_config_var("EXT_SUFFIX"))}
    File "/usr/lib/python2.7/re.py", line 210, in escape
      s = list(pattern)
  TypeError: 'NoneType' object is not iterable
  ----------------------------------------
ERROR: Command errored out with exit status 1: /home/pc_user/.venvs/venv/bin/python /home/pc_user/.venvs/venv/lib/python2.7/site-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /tmp/tmp7q7z4L Check the logs for full command output.

 

나랑 완전 100% 같은 경우는 아닌데, 이분은 path 가 root 부터 시작하는 걸 보니 리눅스의 냄새다

 

거기다 가장 큰 단서는 _in_process.py 에서 롤린하다가 에러가 낫다는건데, ㅇ ㅣ부분에서 답변을 살펴보면

 

Python 2.7 is not supported anymore in opencv-python-4.3.0.38. Support was dropped in 4.3.0.36; see this issue.

The workaround I found was to install opencv-python version 4.2.0.32 (which is the latest supported for Python 2.7, see this for all releases) like this:

 

버전이 맘에 안든다는 이야기다

 

python -m pip install opencv-python==4.2.0.32

이렇게 해줫더니 깔끔하게 됫다.

 

stackoverflow.com/questions/63346648/python-2-7-installing-opencv-via-pip-virtual-environment

 

 

 

아! 추가적으로 혹시 모르니까

setting.json 에서 한줄 추가해준다.

"python.linting.pylintArgs": ["--extension-pkg-whitelist=cv2"] 

 

4.2 수

파이썬에서 수를 나타내는 데이터 유형에는 정수, 실수, 복소수 등 여러 가지가 있다. 이들은 모두 수에 속하지만, 표현할 수 있는 수의 종류와 범위가 다르다. 하나씩 살펴보자.

4.2.1 정수

정수(integer, 줄여서 int)는 자연수에 음양 부호(+, -)가 붙은 것이다. 비트 하나로 부호를 표현하고, 여러 개의 비트 묶음으로 자연수를 표현한다.

여러분은 이미 파이썬에서 정수를 여러 번 사용해 보았다. 파이썬에서 소수점 없이 입력된 수, 즉 0, -15 같은 표현은 모두 정수다. 다음은 대화식 셸에 정수를 입력해 본 것이다.

코드 4-1 정수의 예

>>> 1000 # 양의 정수 1000

>>> -1000 # 음의 정수 -1000

파이썬은 자릿수가 큰 수도 취급할 수 있다. 작은 수를 입력할 때와 마찬가지로 그냥 코드에 입력하면 된다.

코드 4-2 큰 정수

>>> 1000000000

1000000000

일상 생활에서는 큰 수를 알아보기 쉽게 세 자리마다 쉼표를 붙여 1,000,000,000 처럼 표기하곤 한다. 파이썬 코드로는 쉼표 대신 밑줄(_)을 하나씩 붙여 표기할 수 있다.

코드 4-3 큰 수를 알아보기 쉽게 표기하는 방법

>>> 1_000_000_000 # 1000000000과 동일하다

1000000000

팔진법과 십육진법

정수는 팔진법이나 십육진법으로도 표현할 수 있다. 팔진수는 0o로 시작하고, 십육진수는 0x로 시작한다. 0o77는 팔진수 77, 0xff는 십육진수 ff다.

코드 4-4 팔진법과 십육진법으로 정수 표현하기

>>> 0o77 # 팔진수 77 63 >>> 0xff # 십육진수 ff 255 >>> 255 == 0xff # 진법이 달라도 같은 정수다 True

컴퓨터 내부에서는 모든 수를 이진법으로 다룬다. 코드에서 어떤 진법으로 수를 표기하든 이진수가 되므로 컴퓨터에게는 차이가 없다. 그러니 가장 사용하기 편리한 십진법을 사용하면 된다. 십육진법과 팔진법은 비트를 직접 다루거나 색상 정보를 표현하는 등 특수한 경우에 가끔씩 사용된다. 다른 사람의 코드를 읽을 때 “아, 십육진수구나” 하고 알아볼 수 있으면 충분하다.

4.2.2 실수

실수는 -1.0, 3.1415처럼 소수점 아래까지 표현할 수 있는 수다. 1.0은 실수 유형 데이터로, 정수 유형 데이터인 1과는 구별된다.

코드 4-5 실수의 표현

>>> 3.1415 3.1415

파이썬에서는 부동소수점 수(floating point number, 줄여서 float)라는 데이터 유형으로 실수를 다룬다. 부동소수점 수는 ‘소수점이 움직이는 수’라는 뜻이다. 이게 무슨 뜻인지는 곧이어 설명한다. 편의상 부동소수점 수를 그냥 실수라고 부를 때가 많다.

과학 표기법

부동소수점 수를 이해하기 위해 과학 표기법에 관해 잠깐 알아보자. 과학 표기법이란 매우 작은 수와 매우 큰 수를 다루는 일이 많은 과학 분야에서 수를 표기하는 방법이다. 전자계산기에 매우 큰 수를 입력하면 화면에 ‘1.234e5’ 같은 수가 출력되는 것을 볼 수 있다. 과학 표기법으로 표기된 수다.

과학 표기법은 수를 가수와 지수로 나누어 적는 방법이다. 1.234e5에서 e를 중심으로 앞의 수(1.234)는 가수, 뒤의 수(5)는 지수다. 이 수가 실제로 나타내는 값은 가수의 소수점 위치를 지수만큼 오른쪽으로 옮겨 구할 수 있다. 1.234의 소수점을 다섯 칸 오른쪽으로 옮기면 123400.0이 된다. 지수가 음수라면 소수점을 왼쪽으로 옮긴다.

파이썬에서도 과학 표기법으로 실수를 나타낼 수 있다. e를 구분자로 하여 가수e지수로 표기하면 된다.

코드 4-6 과학 표기법으로 실수 표기

>>> 1.23e0 # 1.23 * 10 ^ 0 1.23 >>> 1.23e6 # 1.23 * 10 ^ 6 1230000.0 >>> 1.23e-4 # 1.23 * 10 ^ -4 0.000123

프로그램에 과학 표기법으로 수를 표기할 일이 많지는 않을 것이다. 하지만 연산 결과가 크거나 작을 때 과학 표기법으로 출력되는 경우가 종종 있으니 눈여겨 봐 두는 것도 좋겠다.

과학 표기법은 컴퓨터의 실수 표현 방식과도 관련이 있다. 컴퓨터는 실수를 기억할 때 수를 부호, 지수, 가수로 나누어 각각 비트 묶음에 담아 기억한다. 그렇게 기억해 둔 수에서, 가수를 지수만큼 소수점 이동시키면 실제 값을 구할 수 있다. 소수점의 위치가 움직이는 수라는 뜻의 ‘부동소수점 수’라는 이름도 이 방법에서 유래한 것이다.

실수의 정밀도 문제

수학의 세계에서는 정수가 실수에 포함되는 개념이다. 하지만 프로그래밍에서는 정수와 실수를 서로 다른 유형으로 구별한다. 정수도 실수로 통일해서 취급하면 편리할텐데, 왜 구별하는 것일까? 비트로 정수와 실수를 표현하는 방법이 다르기 때문이다.

정수는 비트를 이용해 정확하게 표현할 수 있다. 하지만 실수는 비트로 정확하게 표현하지 못한다. 이진법에서는 딱 나누어 떨어지는 소수가 별로 없기 때문이다. 0.1이라는 간단한 수조차도 나누어 떨어지지 않는다. (1을 2로 여러 번 나누어서 0.1을 만들려면 몇 번 나누어야 하는지 계산해 보라.) 이런 수는 이진수로는 순환소수가 되며, 비트로 정확하게 표현할 수 없으므로 아무리 정밀하게 표현하려 해도 오차가 있을 수밖에 없다. 다음 코드는 이 문제를 대화식 셸에서 확인해 본 것이다. 파이썬에서 실수를 연산하여 실수 연산 오차를 확인해 보자.

코드 4-7 파이썬의 실수 오차

>>> 1.1 - 1.0 # 계산 결과는 0.1이어야 하지만... 0.10000000000000009

1.1 - 1.0의 계산 결과는 0.1이어야 하지만 실제로는 0.10000000000000009가 나왔다. 매우 미세하지만 오차가 발생했다.

실수를 표현하는 데 사용되는 비트의 양을 늘릴 수록 오차의 크기는 작아진다. 하지만 용량을 아무리 늘려도 오차가 완전히 없어지지는 않는다. 무한히 반복되는 순환소수를 종이에 정확하게 적으려면 무한한 크기의 종이에 무한히 적어야 한다. 컴퓨터의 자원은 유한하기 때문에 실수를 아무리 정밀하게 표현하려 해도 근사치를 사용할 수밖에 없다.

그러면 프로그래밍 할 때 신경써야 할 것은 무엇일까? 1.1 - 1.0 == 0.1처럼 실수를 동등 연산자로 비교하지 말아야 한다. 0.00009 < 1.1 - 1.0 < 0.100001처럼 일정한 오차범위를 정해서 비교하는 것이 더 적절하다.

정수와 실수는 각자의 특징과 한계가 있기 때문에 대부분의 프로그래밍 언어에서 서로 다른 유형으로 구별되어 있다. 처리하려는 데이터에 올바른 유형이 정수인지 실수인지 잘 파악해야 한다.

무한대

실수 데이터에는 양의 무한대와 음의 무한대가 있다. 양의 무한대와 음의 무한대를 나타내는 데이터는 각각 float('inf')와 float('-inf')라는 표현을 이용해 만든다. 무한대는 다른 모든 수보다 크거나, 다른 모든 수보다 작은 수를 표현해야 할 때 사용할 수 있다.

코드 4-8 무한대

>>> float('inf') # 양의 무한대 inf >>> float('-inf') # 음의 무한대 -inf >>> 1e100 < float('inf') # 무한대는 다른 모든 실수보다 크다 True >>> 1e309 # 너무 큰 실수는 무한대로 평가된다 inf >>> 1e-324 # 너무 0에 가까운 실수는 0으로 평가된다 0.0

실수를 나타내는 데 사용한 용량이 제한되어 있으므로, 너무 큰 실수는 무한대로 평가되어 버리고 너무 0에 가까운 수(무한소)는 0으로 평가되어 버린다. 곤란한 일이라고 생각할 수도 있겠지만 일반적인 프로그래밍 상황에서 이런 수를 취급할 일은 거의 없다고 봐도 무방하다. 관측할 수 있는 우주에 존재하는 모든 수소 원자의 수가 1e81개 이하라고 한다.

4.2.3 복소수

파이썬의 수치 데이터 유형에는 앞에서 설명한 정수와 부동소수점 수 외에 복소수(complex number, 줄여서 complex)가 있다. 복소수는 고등학교 수학에서 등장한다. 아직 복소수를 배우지 않았다면 이 절의 내용은 넘어가도 된다.

수학의 표기법에서 복소수는 ‘1+2i’와 같이 실수부와 허수부를 나누어 표기한다. 이 때 ‘i’는 제곱해서 -1이 되는 가상의 상수이며 복소수의 허수부를 나타내기 위한 기호로 사용된다.

파이썬에서 복소수를 표현할 때는 1+2j처럼 i만 j로 바꾸어 표기하면 된다.

코드 4-9 복소수의 표현과 연산

>>> 1-2j # 실수부가 1, 허수부가 -2인 복소수 (1-2j) >>> (1-2j).real # 복소수의 실수부 1.0 >>> (1-2j).imag # 복소수의 허수부 -2.0

복소수에 .real을 계산하면 실수부를, .imag를 계산하면 허수부를 구할 수 있다. 단, 소수점과 구별하기 위해 수를 괄호로 감싸주어야 한다.

4.2.4 수의 연산

데이터는 유형에 따라 가능한 연산이 정해져 있다. 정수, 실수, 복소수는 데이터 유형이 서로 다르지만, 넓은 의미에서 모두 수이기 때문에 연산을 서로 공유한다.

수로 할 수 있는 연산은 대부분 2장에서 살펴보았다. 수는 사칙연산, 거듭제곱, 몫과 나머지 계산, 반올림 계산, 절대값 계산 등이 가능하다. 그리고 방금 배운 복소수의 실수부와 허수부를 구하는 연산도 있다. 이 연산들은 정수, 실수, 복소수 모두 공통적으로 사용 가능하다. 심지어 정수를 반올림하거나 정수의 실수부를 구하는 것도 할 수 있다. 다음 예제를 보자.

코드 4-10 수 유형을 위한 연산은 통용된다

>>> round(10) # 실수와 마찬가지로 정수도 반올림이 된다 10 >>> (10).real # 정수에서 복소수의 실수부를 구하는 연산도 가능하다 10

정수를 반올림하거나 정수의 실수부를 구하는 연산은 쓸모없어 보일 수 있다. 하지만 정수는 실수에 포함되고 실수는 복소수에 포함되므로 수를 위한 연산이 공통적으로 가능한 것은 논리적으로 타당하다. 어떤 변수에 저장된 수가 정수인지 실수인지 복소수인지 모른 채 연산을 해야 한다면 이런 특성이 유용할 것이다.

정수와 실수를 더하거나 실수와 복소수를 곱하는 등 서로 다른 유형의 수를 함께 계산하는 것도 가능하다. 이 때 연산 결과는 더 넓은 범위의 수 유형으로 계산된다. 정수와 실수를 계산하면 실수가 되고, 실수와 복소수를 계산하면 복소수가 된다.

코드 4-11 서로 다른 유형의 수를 함께 연산하기

>>> 10 + 0.5 # 정수와 실수의 연산 -> 실수 10.5 >>> 0.5 * 1+2j # 실수와 복소수의 연산 -> 복소수 (0.5+2j)

그렇다면 수 데이터에 적용할 수 없는 연산에는 무엇이 있을까? 아직 소개한 적은 없지만 곧 배우게 될 텍스트 데이터의 대문자 변경 연산(upper())을 수에 적용해 보자.

코드 4-12 수에 적용할 수 없는 연산의 예

>>> (10).upper() # 텍스트를 위한 연산은 오류를 발생시킨다 AttributeError: 'int' object has no attribute 'upper'

(10).upper()는 10이라는 수를 대문자로 바꾸는 연산이다. 수를 대문자로 바꾼다는 것은 논리적으로도 말이 안 되고, 수 데이터 유형에서 이 연산을 지원하지도 않는다. 그래서 오류가 발생한 것이다.

연습문제

연습문제 4-1 프로그래머의 나이 표기

프로그래머 세 사람이 자신의 나이를 말하고 있다.

프로그래머 A: “저는 0x7d0년에 태어났습니다. 올해로 0x12살이 되었네요.” 프로그래머 B: “그러시군요. 저는 올해 0o22세입니다.” 프로그래머 C: “저는 18살입니다.”

세 사람의 출생년은 각각 언제인가?

힌트: 대화식 셸에 팔진수 또는 십육진수를 입력하면 십진수로 출력된다.

연습문제 4-2 과학 표기법

-252.87을 과학 표기법으로 나타내 보아라.

연습문제 4-3 융통성 있는 실수 비교 함수

두 실수가 거의 같은지 검사하는 함수 almost_equal()을 정의하라. 이 함수는 실수 두 개를 입력받아 두 실수의 차이(오차허용범위)가 0.0001 미만이면 True를 그렇지 않으면 False를 반환한다. 또, 할 수 있다면 함수를 호출할 때 오차허용범위를 지정하도록 정의해 보라.

1. Minimax Algorithm

Minimax is a decision rule used in decision theory, game theory, statistics and philosophy for minimizing the possible loss for a worst case (maximum loss) scenario.

 

틱-택-토, 체스, 오목과 같은 게임의 인공지능은 어떻게 만들어질까?

 

저런 게임들은 멀리 보는것이 중요하다. 상대방을 파악하고 예상해서 장기적으로 유리하게 이끌어 가야 이기게 된다.

 

컴퓨터는 게임의 판도를 읽을 줄 모르기 때문에, 게임판의 상태를 점수로 변환시키는 과정이 필요하다. 예를 들면 체스에서 폰은 1점, ..., 퀸은 9점 하는 것과 같이 이 과정을 '평가한다'고 하자. 평가하는 규칙을 정한다면 게임판의 모든 상태를 점수로 바꿀 수 있다.

 

여기에 "AI가 유리하면 큰 점수, 유저가 유리하면 작은 점수"가 되도록 규칙을  정해주면 된다. (사실 어떻게 보면 이 과정이 가장 어렵다.)

 

컴퓨터가 이길 수 있는 방법은, 지금 게임판의 상태에서 변경 가능한 모든 경우를 평가해서, 가장 높은 점수의 길로 가는 것이다. 그런데, 이런 상황이라면?

 

 

이때, 컴퓨터인 흰색 퀸이, 다음 차례에 가장 유리해지도록 C5로 가서 폰을 먹는다면, 곧 D6의 폰에게 퀸을 잃게 될 것이다. 이처럼, 평가해야할 게임판은 바로 당장의 게임판이 아닌, 몇수 후의 게임판을 평가해서, 가장 높은 점수의 평가판을 향해 다음 수를 두어야 한다.

 

하지만 그럴때 상대편은 항상 우리에게 최악인 수를 골라서 간다. 왜냐면 그래야 자기들이 이기기 때문이니까. 그래서 우리는 상대편이 던저주는 최악의 수 중에서, 가장 최선의 수를 골라야 한다.

 

그래서 이용되는 알고리즘이 Minimax 알고리즘이다.

 

 

위의 그림을 분석해보자. 현재 상태은 가장 위에 있는 0번째 상황이고, 이 인공지능은 4수를 내다볼 수 있다. 4수째의 상태 중에서 최고의 상태은 가장 왼쪽의 점수가 10인 상태로 가는 것이다. 하지만 그렇다고 현재 선택에서 왼쪽길을 선택한다면, 상대방은 자신에게 가장 유리한 점수가 -10인 상태로 갈 것이다. 결국 본전도 못찾은것. 결국 가장 나은 길은 오른쪽 길이다.

 

이렇게 분석하는 Minimax 알고리즘을 간단한 애니메이션으로 보자.

 

위키피디아의 의사 코드도 살펴보자.

function minimax(node, depth, maximizingPlayer)
    if depth = 0 or node is a terminal node
        return the heuristic value of node
    if maximizingPlayer
        bestValue := -∞
        for each child of node
            val := minimax(child, depth - 1, FALSE))
            bestValue := max(bestValue, val);
        return bestValue
    else
        bestValue := +∞
        for each child of node
            val := minimax(child, depth - 1, TRUE))
            bestValue := min(bestValue, val);
        return bestValue

(* Initial call for maximizing player *)
minimax(origin, depth, TRUE)

 

그런데, 실제 게임은 가짓수가 어마어마하게 많다. 한가지 상태에서 10가지 경우가 나온다면, 3수 앞을 내다보는 인공지능은 1000가지 상태를, 6수 앞을 내다보는 인공지능은 1000000가지 상태를 평가해야 한다. 그래서 저 연산 중 불필요한 연산을 가지치듯이 버리는 알고리즘인 알파-베타 가지치기(Alpha-beta pruning)이 등장한다.

 

2. 알파-베타 가지치기

 

기본 Minimax 알고리즘은 모든 노드를 방문해서 평가해야 했지만, 실제로는 그렇지 않아도 되는 경우가 존재한다.

  • 자신이 그 경우를 택하면 자신이 불리해지는 것이 확정된 경우
  • 어떠한 경우가 자신에게 유리한 것이 확정되어 상대가 그것을 택하지 않을 확률이 높은 경우

두 경우는 애써 모든 자식노드를 검사해봐야 선택하지 않을 확률이 매우 높다. 그래서 저러한 경우가 확정되면 그 노드의 자식노드에 대한 평가를 당장 중지하여야만 불필요한 연산을 줄일 수 있다.

 

약간 길지만 자세한 동영상 설명을 보자.

 

그리고 위키피디아의 의사코드를 음미해보자.

function alphabeta(node, depth, α, β, maximizingPlayer)
    if depth = 0 or node is a terminal node
        return the heuristic value of node
    if maximizingPlayer
        for each child of node
            α := max(α, alphabeta(child, depth - 1, α, β, FALSE))
            if β ≤ α
                break (* β cut-off *)
        return α
    else
        for each child of node
            β := min(β, alphabeta(child, depth - 1, α, β, TRUE))
            if β ≤ α
                break (* α cut-off *)
        return β
(* Initial call *)
alphabeta(origin, depth, -, +, TRUE)

 

위의 동영상을 보면, Alpha 는 이전(상위) 상태들 중에서 AI에게 가장 유리한 상태의 점수, Beta 는 이전(상위) 상태들 중에서 상대방에게 가장 유리한 상태의 점수이다.

 

Alpha cut-off  자신이 상대방보다 불리하여, 자신이 그 경우를 선택하지 않을 때 불필요한 연산을 잘라내는 것이고, Beta cut-off  자신이 상대방보다 유리하여, 상대방이 그 경우를 선택하지 않을 확률이 높을 때 불필요한 연산을 잘라내는 것이다. 둘의 차이점을 잘 알아두자.

 

3. 마무리

 

Alpha-beta pruning 외에도 Negascout 이나 MTD-f 와 같은 최적화 알고리즘이 있다고 한다. 이건 나중에 알아보자.

 

AS3으로 직접 Reversi의 인공지능을 구현해보았다. Depth가 커질수록 강한 인공지능이 되지만 랙은 기하급수적으로 커진다. 5 정도 되면 느려지기 시작하고 6 이상은 정상적인 플레이가 힘들정도..

 

popungpopung.tistory.com/10

+ Recent posts