我已经了解到,可以在Python中向现有对象(即,不在类定义中)添加方法。

我明白这样做并不总是好的。但你怎么能做到这一点呢?


当前回答

如何从类的实例恢复类

class UnderWater:
    def __init__(self):
        self.net = 'underwater'

marine = UnderWater() # Instantiate the class

# Recover the class from the instance and add attributes to it.
class SubMarine(marine.__class__):  
    def __init__(self):
        super().__init__()
            self.sound = 'Sonar'
    
print(SubMarine, SubMarine.__name__, SubMarine().net, SubMarine().sound)

# Output
# (__main__.SubMarine,'SubMarine', 'underwater', 'Sonar')

其他回答

如果有什么帮助的话,我最近发布了一个名为Gorilla的Python库,以使猴子修补过程更加方便。

使用函数needle()修补名为guinepig的模块如下:

import gorilla
import guineapig
@gorilla.patch(guineapig)
def needle():
    print("awesome")

但它还处理了文档中常见问题解答中所示的更有趣的用例。

该代码在GitHub上可用。

整合Jason Pratt和社区wiki的答案,看看不同绑定方法的结果:

特别注意将绑定函数添加为类方法是如何工作的,但引用范围不正确。

#!/usr/bin/python -u
import types
import inspect

## dynamically adding methods to a unique instance of a class


# get a list of a class's method type attributes
def listattr(c):
    for m in [(n, v) for n, v in inspect.getmembers(c, inspect.ismethod) if isinstance(v,types.MethodType)]:
        print m[0], m[1]

# externally bind a function as a method of an instance of a class
def ADDMETHOD(c, method, name):
    c.__dict__[name] = types.MethodType(method, c)

class C():
    r = 10 # class attribute variable to test bound scope

    def __init__(self):
        pass

    #internally bind a function as a method of self's class -- note that this one has issues!
    def addmethod(self, method, name):
        self.__dict__[name] = types.MethodType( method, self.__class__ )

    # predfined function to compare with
    def f0(self, x):
        print 'f0\tx = %d\tr = %d' % ( x, self.r)

a = C() # created before modified instnace
b = C() # modified instnace


def f1(self, x): # bind internally
    print 'f1\tx = %d\tr = %d' % ( x, self.r )
def f2( self, x): # add to class instance's .__dict__ as method type
    print 'f2\tx = %d\tr = %d' % ( x, self.r )
def f3( self, x): # assign to class as method type
    print 'f3\tx = %d\tr = %d' % ( x, self.r )
def f4( self, x): # add to class instance's .__dict__ using a general function
    print 'f4\tx = %d\tr = %d' % ( x, self.r )


b.addmethod(f1, 'f1')
b.__dict__['f2'] = types.MethodType( f2, b)
b.f3 = types.MethodType( f3, b)
ADDMETHOD(b, f4, 'f4')


b.f0(0) # OUT: f0   x = 0   r = 10
b.f1(1) # OUT: f1   x = 1   r = 10
b.f2(2) # OUT: f2   x = 2   r = 10
b.f3(3) # OUT: f3   x = 3   r = 10
b.f4(4) # OUT: f4   x = 4   r = 10


k = 2
print 'changing b.r from {0} to {1}'.format(b.r, k)
b.r = k
print 'new b.r = {0}'.format(b.r)

b.f0(0) # OUT: f0   x = 0   r = 2
b.f1(1) # OUT: f1   x = 1   r = 10  !!!!!!!!!
b.f2(2) # OUT: f2   x = 2   r = 2
b.f3(3) # OUT: f3   x = 3   r = 2
b.f4(4) # OUT: f4   x = 4   r = 2

c = C() # created after modifying instance

# let's have a look at each instance's method type attributes
print '\nattributes of a:'
listattr(a)
# OUT:
# attributes of a:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FD88>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FD88>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FD88>>

print '\nattributes of b:'
listattr(b)
# OUT:
# attributes of b:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x000000000230FE08>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x000000000230FE08>>
# f0 <bound method C.f0 of <__main__.C instance at 0x000000000230FE08>>
# f1 <bound method ?.f1 of <class __main__.C at 0x000000000237AB28>>
# f2 <bound method ?.f2 of <__main__.C instance at 0x000000000230FE08>>
# f3 <bound method ?.f3 of <__main__.C instance at 0x000000000230FE08>>
# f4 <bound method ?.f4 of <__main__.C instance at 0x000000000230FE08>>

print '\nattributes of c:'
listattr(c)
# OUT:
# attributes of c:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002313108>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002313108>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002313108>>

就我个人而言,我更喜欢外部ADDMETHOD函数路由,因为它也允许我在迭代器中动态分配新的方法名。

def y(self, x):
    pass
d = C()
for i in range(1,5):
    ADDMETHOD(d, y, 'f%d' % i)
print '\nattributes of d:'
listattr(d)
# OUT:
# attributes of d:
# __init__ <bound method C.__init__ of <__main__.C instance at 0x0000000002303508>>
# addmethod <bound method C.addmethod of <__main__.C instance at 0x0000000002303508>>
# f0 <bound method C.f0 of <__main__.C instance at 0x0000000002303508>>
# f1 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f2 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f3 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
# f4 <bound method ?.y of <__main__.C instance at 0x0000000002303508>>
from types import MethodType

def method(self):
   print 'hi!'


setattr( targetObj, method.__name__, MethodType(method, targetObj, type(method)) )

使用此选项,可以使用self指针

前言-关于兼容性的说明:其他答案可能只在Python2-这个答案应该在Python2和3中运行得很好。如果只编写Python3,您可能会忽略显式继承自对象,否则代码应该保持不变。

向现有对象实例添加方法我已经了解到,可以在Python中向现有对象(例如,不在类定义中)添加方法。我知道这样做并不总是一个好的决定。但是,一个人怎么做呢?

是的,有可能-但不建议

我不建议这样做。这是个坏主意。不要这样做。

以下是几个原因:

您将为每个执行此操作的实例添加一个绑定对象。如果经常这样做,可能会浪费大量内存。绑定方法通常只在其调用的短时间内创建,然后在自动垃圾收集时停止存在。如果手动执行此操作,则将有一个引用绑定方法的名称绑定,这将防止其在使用时进行垃圾收集。给定类型的对象实例通常在该类型的所有对象上都有其方法。如果在其他地方添加方法,某些实例将具有这些方法,而其他实例则没有。程序员不会预料到这一点,你可能会违反最不意外的规则。由于有其他真正好的理由不这样做,如果你这样做,你还会给自己带来坏名声。

因此,我建议你不要这样做,除非你有充分的理由。在类定义中定义正确的方法要好得多,或者直接对类进行猴式修补,如下所示:

Foo.sample_method = sample_method

不过,既然这很有启发性,我将向你展示一些这样做的方法。

如何做到这一点

这是一些设置代码。我们需要一个类定义。它可以进口,但真的没关系。

class Foo(object):
    '''An empty class to demonstrate adding a method to an instance'''

创建实例:

foo = Foo()

创建要添加到其中的方法:

def sample_method(self, bar, baz):
    print(bar + baz)

方法零(0)-使用描述符方法__get__

函数上的点查找使用实例调用函数的__get__方法,将对象绑定到方法,从而创建“绑定方法”

foo.sample_method = sample_method.__get__(foo)

现在:

>>> foo.sample_method(1,2)
3

方法一-types.MethodType

首先,导入类型,我们将从中获取方法构造函数:

import types

现在我们将该方法添加到实例中。为此,我们需要类型模块中的MethodType构造函数(我们在上面导入了它)。

types.MethodType(在Python 3中)的参数签名是(function,instance):

foo.sample_method = types.MethodType(sample_method, foo)

和用法:

>>> foo.sample_method(1,2)
3

附带地,在Python 2中,签名是(函数、实例、类):

foo.sample_method = types.MethodType(sample_method, foo, Foo)

方法二:词汇绑定

首先,我们创建一个将方法绑定到实例的包装函数:

def bind(instance, method):
    def binding_scope_fn(*args, **kwargs): 
        return method(instance, *args, **kwargs)
    return binding_scope_fn

用法:

>>> foo.sample_method = bind(foo, sample_method)    
>>> foo.sample_method(1,2)
3

方法三:functools.partial

分部函数将第一个参数应用于函数(以及可选的关键字参数),然后可以用剩余的参数(以及重写关键字参数)调用。因此:

>>> from functools import partial
>>> foo.sample_method = partial(sample_method, foo)
>>> foo.sample_method(1,2)
3    

当您认为绑定方法是实例的部分函数时,这是有意义的。

作为对象属性的未绑定函数-为什么不起作用:

如果我们尝试以与将sample_method添加到类中相同的方式添加sample_methods,它将与实例绑定,并且不会将隐式self作为第一个参数。

>>> foo.sample_method = sample_method
>>> foo.sample_method(1,2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sample_method() takes exactly 3 arguments (2 given)

我们可以通过显式传递实例(或任何东西,因为此方法实际上不使用自参数变量)来使未绑定函数工作,但它与其他实例的预期签名不一致(如果我们正在对该实例进行猴子修补):

>>> foo.sample_method(foo, 1, 2)
3

结论

你现在知道有几种方法可以做到这一点,但认真地说,不要这样做。

感谢Arturo!你的回答让我步入正轨!

根据Arturo的代码,我编写了一个小类:

from types import MethodType
import re
from string import ascii_letters


class DynamicAttr:
    def __init__(self):
        self.dict_all_files = {}

    def _copy_files(self, *args, **kwargs):
        print(f'copy {args[0]["filename"]} {args[0]["copy_command"]}')

    def _delete_files(self, *args, **kwargs):
        print(f'delete {args[0]["filename"]} {args[0]["delete_command"]}')

    def _create_properties(self):
        for key, item in self.dict_all_files.items():
            setattr(
                self,
                key,
                self.dict_all_files[key],
            )
            setattr(
                self,
                key + "_delete",
                MethodType(
                    self._delete_files,
                    {
                        "filename": key,
                        "delete_command": f'del {item}',
                    },
                ),
            )
            setattr(
                self,
                key + "_copy",
                MethodType(
                    self._copy_files,
                    {
                        "filename": key,
                        "copy_command": f'copy {item}',
                    },
                ),
            )
    def add_files_to_class(self, filelist: list):
        for _ in filelist:
            attr_key = re.sub(rf'[^{ascii_letters}]+', '_', _).strip('_')
            self.dict_all_files[attr_key] = _
        self._create_properties()
dy = DynamicAttr()
dy.add_files_to_class([r"C:\Windows\notepad.exe", r"C:\Windows\regedit.exe"])

dy.add_files_to_class([r"C:\Windows\HelpPane.exe", r"C:\Windows\win.ini"])
#output
print(dy.C_Windows_HelpPane_exe)
dy.C_Windows_notepad_exe_delete()
dy.C_Windows_HelpPane_exe_copy()
C:\Windows\HelpPane.exe
delete C_Windows_notepad_exe del C:\Windows\notepad.exe
copy C_Windows_HelpPane_exe copy C:\Windows\HelpPane.exe

此类允许您随时添加新的属性和方法。

编辑:

这里有一个更普遍的解决方案:

import inspect
import re
from copy import deepcopy
from string import ascii_letters


def copy_func(f):
    if callable(f):
        if inspect.ismethod(f) or inspect.isfunction(f):
            g = lambda *args, **kwargs: f(*args, **kwargs)
            t = list(filter(lambda prop: not ("__" in prop), dir(f)))
            i = 0
            while i < len(t):
                setattr(g, t[i], getattr(f, t[i]))
                i += 1
            return g
    dcoi = deepcopy([f])
    return dcoi[0]


class FlexiblePartial:
    def __init__(self, func, this_args_first, *args, **kwargs):

        try:
            self.f = copy_func(func)  # create a copy of the function
        except Exception:
            self.f = func
        self.this_args_first = this_args_first  # where should the other (optional) arguments be that are passed when the function is called
        try:
            self.modulename = args[0].__class__.__name__  # to make repr look good
        except Exception:
            self.modulename = "self"

        try:
            self.functionname = func.__name__  # to make repr look good
        except Exception:
            try:
                self.functionname = func.__qualname__  # to make repr look good
            except Exception:
                self.functionname = "func"

        self.args = args
        self.kwargs = kwargs

        self.name_to_print = self._create_name()  # to make repr look good

    def _create_name(self):
        stra = self.modulename + "." + self.functionname + "(self, "
        for _ in self.args[1:]:
            stra = stra + repr(_) + ", "
        for key, item in self.kwargs.items():
            stra = stra + str(key) + "=" + repr(item) + ", "
        stra = stra.rstrip().rstrip(",")
        stra += ")"
        if len(stra) > 100:
            stra = stra[:95] + "...)"
        return stra

    def __call__(self, *args, **kwargs):
        newdic = {}
        newdic.update(self.kwargs)
        newdic.update(kwargs)
        if self.this_args_first:
            return self.f(*self.args[1:], *args, **newdic)

        else:

            return self.f(*args, *self.args[1:], **newdic)

    def __str__(self):
        return self.name_to_print

    def __repr__(self):
        return self.__str__()


class AddMethodsAndProperties:
    def add_methods(self, dict_to_add):
        for key_, item in dict_to_add.items():
            key = re.sub(rf"[^{ascii_letters}]+", "_", str(key_)).rstrip("_")
            if isinstance(item, dict):
                if "function" in item:  # for adding methods
                    if not isinstance(
                        item["function"], str
                    ):  # for external functions that are not part of the class
                        setattr(
                            self,
                            key,
                            FlexiblePartial(
                                item["function"],
                                item["this_args_first"],
                                self,
                                *item["args"],
                                **item["kwargs"],
                            ),
                        )

                    else:
                        setattr(
                            self,
                            key,
                            FlexiblePartial(
                                getattr(
                                    self, item["function"]
                                ),  # for internal functions - part of the class
                                item["this_args_first"],
                                self,
                                *item["args"],
                                **item["kwargs"],
                            ),
                        )
            else:  # for adding props
                setattr(self, key, item)

让我们测试一下:

class NewClass(AddMethodsAndProperties): #inherit from AddMethodsAndProperties to add the method add_methods
    def __init__(self):
        self.bubu = 5

    def _delete_files(self, file): #some random methods 
        print(f"File will be deleted: {file}")

    def delete_files(self, file):
        self._delete_files(file)

    def _copy_files(self, file, dst):
        print(f"File will be copied: {file} Dest: {dst}")

    def copy_files(self, file, dst):
        self._copy_files(file, dst)

    def _create_files(self, file, folder):
        print(f"File will be created: {file} {folder}")

    def create_files(self, file, folder):
        self._create_files(file, folder)

    def method_with_more_kwargs(self, file, folder, one_more):
        print(file, folder, one_more)
        return self


nc = NewClass()
dict_all_files = {
    r"C:\Windows\notepad.exe_delete": {
        "function": "delete_files",
        "args": (),
        "kwargs": {"file": r"C:\Windows\notepad.exe"},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_argsfirst": {
        "function": "delete_files",
        "args": (),
        "kwargs": {"file": r"C:\Windows\notepad.exe"},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_copy": {
        "function": "copy_files",
        "args": (),
        "kwargs": {
            "file": r"C:\Windows\notepad.exe",
            "dst": r"C:\Windows\notepad555.exe",
        },
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_create": {
        "function": "create_files",
        "args": (),
        "kwargs": {"file": r"C:\Windows\notepad.exe", "folder": "c:\\windows95"},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_upper": {
        "function": str.upper,
        "args": (r"C:\Windows\notepad.exe",),
        "kwargs": {},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_method_with_more_kwargs": {
        "function": "method_with_more_kwargs",
        "args": (),
        "kwargs": {"file": r"C:\Windows\notepad.exe", "folder": "c:\\windows95"},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_method_with_more_kwargs_as_args_first": {
        "function": "method_with_more_kwargs",
        "args": (r"C:\Windows\notepad.exe", "c:\\windows95"),
        "kwargs": {},
        "this_args_first": True,
    },
    r"C:\Windows\notepad.exe_method_with_more_kwargs_as_args_last": {
        "function": "method_with_more_kwargs",
        "args": (r"C:\Windows\notepad.exe", "c:\\windows95"),
        "kwargs": {},
        "this_args_first": False,
    },
    "this_is_a_list": [55, 3, 3, 1, 4, 43],
}

nc.add_methods(dict_all_files)


print(nc.C_Windows_notepad_exe_delete)
print(nc.C_Windows_notepad_exe_delete(), end="\n\n")
print(nc.C_Windows_notepad_exe_argsfirst)
print(nc.C_Windows_notepad_exe_argsfirst(), end="\n\n")
print(nc.C_Windows_notepad_exe_copy)
print(nc.C_Windows_notepad_exe_copy(), end="\n\n")
print(nc.C_Windows_notepad_exe_create)
print(nc.C_Windows_notepad_exe_create(), end="\n\n")
print(nc.C_Windows_notepad_exe_upper)
print(nc.C_Windows_notepad_exe_upper(), end="\n\n")
print(nc.C_Windows_notepad_exe_method_with_more_kwargs)
print(
    nc.C_Windows_notepad_exe_method_with_more_kwargs(
        one_more="f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs(
        one_more="f:\\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs(
        one_more="f:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    ),
    end="\n\n",
)
print(nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_first)
print(
    nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_first(
        "f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    ),
    end="\n\n",
)
print(
    nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_first(
        "f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_first(
        "f:\\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_first(
        "f:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    ),
    end="\n\n",
)
print(nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_last)
print(
    nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    ),
    end="\n\n",
)
print(
    nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    ),
    end="\n\n",
)
print(nc.this_is_a_list)
checkit = (
    nc.C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\blaaaaaaaaaaaaaaaaaaaaaaaa"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ"
    )
    .C_Windows_notepad_exe_method_with_more_kwargs_as_args_last(
        "f:\\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    )
)
print(f'nc is checkit? -> {nc is checkit}')


#output:


NewClass.delete_files(self, file='C:\\Windows\\notepad.exe')
File will be deleted: C:\Windows\notepad.exe
None


NewClass.delete_files(self, file='C:\\Windows\\notepad.exe')
File will be deleted: C:\Windows\notepad.exe
None


NewClass.copy_files(self, file='C:\\Windows\\notepad.exe', dst='C:\\Windows\\notepad555.exe')
File will be copied: C:\Windows\notepad.exe Dest: C:\Windows\notepad555.exe
None


NewClass.create_files(self, file='C:\\Windows\\notepad.exe', folder='c:\\windows95')
File will be created: C:\Windows\notepad.exe c:\windows95
None


NewClass.upper(self, 'C:\\Windows\\notepad.exe')
C:\WINDOWS\NOTEPAD.EXE


NewClass.method_with_more_kwargs(self, file='C:\\Windows\\notepad.exe', folder='c:\\windows95')
C:\Windows\notepad.exe c:\windows95 f:\blaaaaaaaaaaaaaaaaaaaaaaaa
C:\Windows\notepad.exe c:\windows95 f:\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ
C:\Windows\notepad.exe c:\windows95 f:\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<__main__.NewClass object at 0x0000000005F199A0>


NewClass.method_with_more_kwargs(self, 'C:\\Windows\\notepad.exe', 'c:\\windows95')
C:\Windows\notepad.exe c:\windows95 f:\blaaaaaaaaaaaaaaaaaaaaaaaa
<__main__.NewClass object at 0x0000000005F199A0>


C:\Windows\notepad.exe c:\windows95 f:\blaaaaaaaaaaaaaaaaaaaaaaaa
C:\Windows\notepad.exe c:\windows95 f:\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ
C:\Windows\notepad.exe c:\windows95 f:\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<__main__.NewClass object at 0x0000000005F199A0>


NewClass.method_with_more_kwargs(self, 'C:\\Windows\\notepad.exe', 'c:\\windows95')
f:\blaaaaaaaaaaaaaaaaaaaaaaaa C:\Windows\notepad.exe c:\windows95
f:\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ C:\Windows\notepad.exe c:\windows95
f:\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX C:\Windows\notepad.exe c:\windows95
<__main__.NewClass object at 0x0000000005F199A0>


f:\blaaaaaaaaaaaaaaaaaaaaaaaa C:\Windows\notepad.exe c:\windows95
f:\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ C:\Windows\notepad.exe c:\windows95
f:\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX C:\Windows\notepad.exe c:\windows95
<__main__.NewClass object at 0x0000000005F199A0>


[55, 3, 3, 1, 4, 43]


f:\blaaaaaaaaaaaaaaaaaaaaaaaa C:\Windows\notepad.exe c:\windows95
f:\ASJVASDFASÇDFJASÇDJFÇASWFJASÇ C:\Windows\notepad.exe c:\windows95
f:\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX C:\Windows\notepad.exe c:\windows95


nc is checkit? -> True