【问题标题】:Python error "unbound method must be called with instance as first argument"Python 错误“必须以实例作为第一个参数调用未绑定的方法”
【发布时间】:2017-07-14 04:23:48
【问题描述】:

现在是我开始使用类的时候了。我一直在寻找另一种方式。昨天我找到了我需要的代码,但它在一个不错的小类中,我不知道如何访问它。我在这里阅读了所有教程甚至类似的解决方案。我只是无法绕过它。我写的唯一部分是“main()”,这是不起作用的部分。我已经重写了几十种方法,但没有一种方法能按照我期望的方式工作。

感谢您的时间和耐心。

所有功劳归于 Nathan Adams - 又名晚餐骨

import socket
import struct

class MinecraftQuery:
    MAGIC_PREFIX = '\xFE\xFD'
    PACKET_TYPE_CHALLENGE = 9
    PACKET_TYPE_QUERY = 0
    HUMAN_READABLE_NAMES = dict(
        game_id     = "Game Name",
        gametype    = "Game Type",
        motd        = "Message of the Day",
        hostname    = "Server Address",
        hostport    = "Server Port",
        map         = "Main World Name",
        maxplayers  = "Maximum Players",
        numplayers  = "Players Online",
        players     = "List of Players",
        plugins     = "List of Plugins",
        raw_plugins = "Raw Plugin Info",
        software    = "Server Software",
        version     = "Game Version",
    )

    def __init__(self, host, port, timeout=10, id=0, retries=2):
        self.addr = (host, port)
        self.id = id
        self.id_packed = struct.pack('>l', id)
        self.challenge_packed = struct.pack('>l', 0)
        self.retries = 0
        self.max_retries = retries

        self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.socket.settimeout(timeout)

    def send_raw(self, data):
        self.socket.sendto(self.MAGIC_PREFIX + data, self.addr)

    def send_packet(self, type, data=''):
        self.send_raw(struct.pack('>B', type) + self.id_packed + self.challenge_packed + data)

    def read_packet(self):
        buff = self.socket.recvfrom(1460)[0]
        type = struct.unpack('>B', buff[0])[0]
        id = struct.unpack('>l', buff[1:5])[0]
        return type, id, buff[5:]

    def handshake(self, bypass_retries=False):
        self.send_packet(self.PACKET_TYPE_CHALLENGE)

        try:
            type, id, buff = self.read_packet()
        except:
            if not bypass_retries:
                self.retries += 1

            if self.retries < self.max_retries:
                self.handshake(bypass_retries=bypass_retries)
                return
            else:
                raise

        self.challenge = int(buff[:-1])
        self.challenge_packed = struct.pack('>l', self.challenge)

    def get_status(self):
        if not hasattr(self, 'challenge'):
            self.handshake()

        self.send_packet(self.PACKET_TYPE_QUERY)

        try:
            type, id, buff = self.read_packet()
        except:
            self.handshake()
            return self.get_status()

        data = {}

        data['motd'], data['gametype'], data['map'], data['numplayers'], data['maxplayers'], buff = buff.split('\x00', 5)
        data['hostport'] = struct.unpack('<h', buff[:2])[0]
        buff = buff[2:]
        data['hostname'] = buff[:-1]

        for key in ('numplayers', 'maxplayers'):
            try:
                data[key] = int(data[key])
            except:
                pass

        return data

    def get_rules(self):
        if not hasattr(self, 'challenge'):
            self.handshake()

        self.send_packet(self.PACKET_TYPE_QUERY, self.id_packed)

        try:
            type, id, buff = self.read_packet()
        except:
            self.retries += 1
            if self.retries < self.max_retries:
                self.handshake(bypass_retries=True)
                return self.get_rules()
            else:
                raise

        data = {}

        buff = buff[11:] # splitnum + 2 ints
        items, players = buff.split('\x00\x00\x01player_\x00\x00') # Shamefully stole from https://github.com/barneygale/MCQuery

        if items[:8] == 'hostname':
            items = 'motd' + items[8:]

        items = items.split('\x00')
        data = dict(zip(items[::2], items[1::2]))

        players = players[:-2]

        if players:
            data['players'] = players.split('\x00')
        else:
            data['players'] = []

        for key in ('numplayers', 'maxplayers', 'hostport'):
            try:
                data[key] = int(data[key])
            except:
                pass

        data['raw_plugins'] = data['plugins']
        data['software'], data['plugins'] = self.parse_plugins(data['raw_plugins'])

        return data

    def parse_plugins(self, raw):
        parts = raw.split(':', 1)
        server = parts[0].strip()
        plugins = []

        if len(parts) == 2:
            plugins = parts[1].split(';')
            plugins = map(lambda s: s.strip(), plugins)

        return server, plugins

def main():
    check = MinecraftQuery.get_status('10.0.10.8',25565)
    print check

main()

【问题讨论】:

  • 您需要先实例化该类,然后再调用其中的方法。首先使用 MinecraftQuery(host, port) 创建一个新实例,其中 host 和 port 显然是主机和端口名称。然后调用那个状态。

标签: python class oop syntax-error


【解决方案1】:

我认为应该如下。试试看它是否有效。

def main():
    check = MinecraftQuery('10.0.10.8', 25565)
    # It calls the __init__() method and constructs an object/instance of the class named 'MinecraftQuery'
    # using the given arguments and associate it with the given identifier 'check'
    check.get_status()
    # Now, this invokes the get_status() method of the instance named 'check'.
    print check

【讨论】:

  • 是的!我不再在 main() 中收到错误。现在我有等待数据包的超时错误。我需要针对不同版本的我的世界进行调整。谢谢!
【解决方案2】:

未绑定的方法是不使用类的实例调用的方法。您的错误意味着您在类而不是实例上调用该方法。所以,你应该先创建一个类的实例,然后调用方法。

【讨论】:

    猜你喜欢
    • 2014-09-10
    • 2014-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-10
    • 2018-05-10
    相关资源
    最近更新 更多